<commit_before>extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use quote::{Tokens, ToTokens};
use syn::*;

#[proc_macro_derive(ColladaElement, attributes(name, attribute, child, text_data))]
pub fn derive(input: TokenStream) -> TokenStream {
    // Parse the string representation.
    let ast = syn::parse_derive_input(&input.to_string()).unwrap();

    // Build the impl.
    match generate_impl(ast) {
        Ok(gen) => {
            gen.parse().unwrap()
        }
        Err(error) => { panic!("{}", error) }
    }
}

fn process_derive_input(input: DeriveInput) -> Result<ElementConfiguration, String> {
    let struct_ident = input.ident;

    // Process the top-level attributes on the type to find the `#[name = "foo"]` attribute.
    // -------------------------------------------------------------------------------------
    let element_name = {
        let mut element_name = None;

        for attribute in input.attrs {
            match attribute.value {
                MetaItem::NameValue(attr_name, Lit::Str(value, _)) => {
                    if attr_name == "name" {
                        element_name = Some(value);
                    }
                }

                _ => {}
            }
        }

        element_name.ok_or(r#"Type must have `#[name = "..."]` attribute when using `#[derive(ColladaElement)]`"#)?
    };

    // Process the body of the type and gather information about attributes and children.
    // ----------------------------------------------------------------------------------
    let mut children = Vec::new();
    let mut attributes = Vec::new();

    let fields = match input.body {
        Body::Enum(_) => { return Err("`#[derive(ColladaElement)]` does not support enum types")?; }

        Body::Struct(VariantData::Struct(fields)) => { fields }

        Body::Struct(VariantData::Tuple(_)) => { return Err("`#[derive(ColladaElement)]` does not support tuple structs")?; }

        Body::Struct(VariantData::Unit) => { Vec::new() }
    };

    for field in fields {
        // We only support struct-structs, so all fields will have an ident.
        let member_name = field.ident.unwrap();

        // Determine the data type and occurrences for the member.
        let path = match field.ty.clone() {
            Ty::Path(None, path) => { path }
            _ => { return Err("`#[derive(ColladaElement)]` doesn't support this member type")?; }
        };

        // Determine the number of occurrences based on the declared type:
        //
        // - `Option<T>` is optional with inner type `T`.
        // - `Vec<T>` is repeating with inner type `T`.
        // - Everything else is required with inner type as declared.
        let segment = path.segments.last().expect("Somehow got an empty path ?_?");

        // We only support angle bracket parameters (because we're only looking for `Option<T>`
        // and `Vec<T>`), so extract the parameter data and throw away all others.
        let parameter_data = match segment.parameters {
            PathParameters::AngleBracketed(ref param) => { param }
            _ => { return Err("Round brace function parameters are not supported")?; }
        };

        // Depending on the number of parameters (0 or 1) we determine the occurrences and the
        // type of the actual data.
        let (occurrences, inner_type) = if parameter_data.types.len() == 0 {
            // No type parameters, so we're not looking at `Option<T>` or `Vec<T>`. That means the
            // child is required and that the field's type is the type of the child data.
            (ChildOccurrences::Required, field.ty)
        } else {
            // There's 1 type parameter, so determine if we're looking at an `Option<T>`, which
            // means optional occurrences of a `T`, or a `Vec<T>`, which means optional many
            // occurrences of `T`.
            let inner_type = parameter_data.types[0].clone();
            match segment.ident.as_ref() {
                "Option" => { (ChildOccurrences::Optional, inner_type) }
                "Vec" => { (ChildOccurrences::OptionalMany, inner_type) }
                _ => { return Err("Unexpected child type with parameters, only `Vec<T>` and `Option<T>` are allowed to have type parameters")?; }
            }
        };

        // Determine the data type of the inner type, e.g. if it's `String` or another ColladaElement.
        let data_type = match inner_type {
            Ty::Path(None, ref path) => {
                let segment = path.segments.last().expect("Somehow got an empty path ?_?");
                if segment.ident.as_ref() == "String" {
                    DataType::TextData(inner_type.clone())
                } else {
                    // Check for a `#[text_data]` attribute.
                    let mut has_text_data_attr = false;
                    for attribute in &field.attrs {
                        if attribute.name() == "text_data" {
                            has_text_data_attr = true;
                        }
                    }

                    if has_text_data_attr {
                        DataType::TextData(inner_type.clone())
                    } else {
                        DataType::ColladaElement(inner_type.clone())
                    }
                }
            },

            _ => { return Err("`#[derive(ColladaElement)]` doesn't support this member type")?; }
        };

        // Determine whether we're looking at a child or an attribute based on whether the member
        // has a `#[child]` or an `#[attribute]` attribute.
        for attribute in field.attrs {
            match attribute.name() {
                "child" => {
                    children.push(Child {
                        member_name: member_name.clone(),
                        element_name: member_name.to_string(),
                        occurrences: occurrences,
                        ty: data_type,
                    });
                    break;
                }

                "attribute" => {
                    let occurrences = match occurrences {
                        ChildOccurrences::Optional => AttributeOccurrences::Optional,
                        ChildOccurrences::Required => AttributeOccurrences::Required,

                        ChildOccurrences::OptionalMany | ChildOccurrences::RequiredMany => {
                            return Err("Attribute may not be repeating, meaning it may not be of type `Vec<T>`".into());
                        }
                    };

                    attributes.push(Attribute {
                        member_name: member_name.clone(),
                        attrib_name: member_name.to_string(),
                        occurrences: occurrences,
                        ty: inner_type,
                    });
                    break;
                }

                _ => {}
            }
        }
    }

    Ok(ElementConfiguration {
        struct_ident: struct_ident,
        element_name: element_name,
        attributes: attributes,
        children: children,
    })
}

struct ElementConfiguration {
    struct_ident: Ident,
    element_name: String,
    attributes: Vec<Attribute>,
    children: Vec<Child>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum AttributeOccurrences {
    Optional,
    Required,
}

struct Attribute {
    member_name: Ident,
    attrib_name: String,
    occurrences: AttributeOccurrences,
    ty: Ty,
}

enum DataType {
    TextData(Ty),
    ColladaElement(Ty),
}

struct Child {
    member_name: Ident,
    element_name: String,
    occurrences: ChildOccurrences,
    ty: DataType,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ChildOccurrences {
    Optional,
    Required,
    OptionalMany,
    RequiredMany,
}

impl ToTokens for ChildOccurrences {
    fn to_tokens(&self, tokens: &mut Tokens) {
        match *self {
            ChildOccurrences::Optional => { tokens.append("Optional"); }

            ChildOccurrences::Required => { tokens.append("Required"); }

            ChildOccurrences::OptionalMany => { tokens.append("Many"); }

            ChildOccurrences::RequiredMany => { tokens.append("RequiredMany"); }
        }
    }
}

fn generate_impl(derive_input: DeriveInput) -> Result<quote::Tokens, String> {
    let ElementConfiguration { struct_ident, element_name, attributes, children } = process_derive_input(derive_input)?;

    // Generate declarations for the member variables of the struct.
    // -------------------------------------------------------------
    let member_decls = {
        let attribs = attributes.iter()
            .map(|attrib| {
                let ident = &attrib.member_name;
                quote! { let mut #ident = None; }
            });
        let childs = children.iter()
            .map(|child| {
                let &Child { ref member_name, occurrences, .. } = child;
                match occurrences {
                    ChildOccurrences::Optional | ChildOccurrences::Required => {
                        quote! { let mut #member_name = None; }
                    }

                    ChildOccurrences::OptionalMany | ChildOccurrences::RequiredMany => {
                        quote! { let mut #member_name = Vec::new(); }
                    }
                }
            });

        quote! {
            #( #attribs )*
            #( #childs )*
        }
    };

    // Generate code for parsing attributes.
    // -------------------------------------
    let attributes_impl = if attributes.len() != 0 {
        let matches = attributes.iter()
            .map(|attrib| {
                let &Attribute { ref member_name, ref attrib_name, ref ty, .. } = attrib;
                quote! {
                    #attrib_name => {
                        let result = #ty::from_str(&*attribute.value)
                            .map_err(|error| Error {
                                position: reader.position(),
                                kind: error.into(),
                            })?;
                        #member_name = Some(result);
                    }
                }
            });

        let attrib_names = attributes.iter()
            .map(|attrib| { &*attrib.attrib_name });

        let required_attribs = attributes.iter()
            .filter(|attrib| { attrib.occurrences == AttributeOccurrences::Required })
            .map(|attrib| {
                let &Attribute { ref member_name, ref attrib_name, .. } = attrib;
                quote! {
                    let #member_name = #member_name.ok_or(Error {
                        position: reader.position(),
                        kind: ErrorKind::MissingAttribute {
                            element: #element_name,
                            attribute: #attrib_name,
                        },
                    })?;
                }
            });

        quote! {
            for attribute in attributes {
                match &*attribute.name.local_name {
                    #( #matches )*

                    attrib_name @ _ => {
                        return Err(Error {
                            position: reader.position(),
                            kind: ErrorKind::UnexpectedAttribute {
                                element: #element_name,
                                attribute: attrib_name.into(),
                                expected: vec![ #( #attrib_names ),* ],
                            },
                        })
                    }
                }
            }

            #( #required_attribs )*
        }
    } else {
        quote! {
            utils::verify_attributes(reader, #element_name, attributes)?;
        }
    };

    // Generate code for parsing children.
    // -----------------------------------
    let children_impl = {
        let decls = children.iter()
            .map(|child| {
                let &Child { ref member_name, ref element_name, occurrences, ref ty } = child;

                let handle_result = match (occurrences, ty) {
                    (ChildOccurrences::Optional, &DataType::TextData(_)) => {
                        quote! {
                            utils::verify_attributes(reader, #element_name, attributes)?;
                            #member_name = utils::optional_text_contents(reader, #element_name)?;
                        }
                    }

                    (ChildOccurrences::Required, &DataType::TextData(_)) => {
                        quote! {
                            utils::verify_attributes(reader, #element_name, attributes)?;
                            let result = utils::required_text_contents(reader, #element_name)?;
                            #member_name = Some(result);
                        }
                    }

                    (ChildOccurrences::OptionalMany, &DataType::TextData(_)) => {
                        quote! {
                            utils::verify_attributes(reader, #element_name, attributes)?;
                            if let Some(result) = utils::optional_text_contents(reader, #element_name)? {
                                #member_name.push(result.parse()?);
                            }
                        }
                    }

                    (ChildOccurrences::RequiredMany, &DataType::TextData(_)) => {
                        quote! {
                            utils::verify_attributes(reader, #element_name, attributes)?;
                            if let Some(result) = utils::optional_text_contents(reader, #element_name)? {
                                #member_name.push(result.parse()?);
                            }
                        }
                    }

                    (ChildOccurrences::Optional, &DataType::ColladaElement(ref ident)) => {
                        quote! {
                            let result = #ident::parse_element(reader, attributes)?;
                            #member_name = Some(result);
                        }
                    }

                    (ChildOccurrences::Required, &DataType::ColladaElement(ref ident)) => {
                        quote! {
                            let result = #ident::parse_element(reader, attributes)?;
                            #member_name = Some(result);
                        }
                    }

                    (ChildOccurrences::OptionalMany, &DataType::ColladaElement(ref ident)) => {
                        quote! {
                            let result = #ident::parse_element(reader, attributes)?;
                            #member_name.push(result);
                        }
                    }

                    (ChildOccurrences::RequiredMany, &DataType::ColladaElement(ref ident)) => {
                        quote! {
                            let result = #ident::parse_element(reader, attributes)?;
                            #member_name.push(result);
                        }
                    }
                };

                quote! {
                    ChildConfiguration {
                        name: #element_name,
                        occurrences: #occurrences,

                        action: &mut |reader, attributes| {
                            #handle_result
                            Ok(())
                        },
                    }
                }
            });

        let required_childs = children.iter()
            .filter_map(|child| {
                let &Child { ref member_name, occurrences, .. } = child;
                if occurrences == ChildOccurrences::Required {
                    Some(quote! {
                        let #member_name = #member_name.expect("Required child was `None`");
                    })
                } else {
                    None
                }
            });

        quote! {
            ElementConfiguration {
                name: #element_name,
                children: &mut [
                    #( #decls ),*
                ],
            }.parse_children(reader)?;

            #( #required_childs )*
        }
    };

    // Generate code to construct final result.
    // ----------------------------------------
    let result_decl = {
        let attribs = attributes.iter()
            .map(|attrib| {
                let ident = &attrib.member_name;
                quote! { #ident: #ident }
            });
        let childs = children.iter()
            .map(|child| {
                let ident = &child.member_name;
                quote! { #ident: #ident }
            });

        quote! {
            Ok(#struct_ident {
                #( #attribs ),*
                #( #childs ),*
            })
        }
    };

    // Put all the pieces together.
    // ----------------------------
    Ok(quote! {
        impl ::utils::ColladaElement for #struct_ident {
            #[allow(unused_imports)]
            fn parse_element<R: ::std::io::Read>(
                reader: &mut ::xml::reader::EventReader<R>,
                attributes: Vec<::xml::attribute::OwnedAttribute>
            ) -> Result<Self> {
                use std::str::FromStr;
                use utils::*;

                #member_decls

                #attributes_impl

                #children_impl

                #result_decl
            }

            fn name() -> &'static str {
                #element_name
            }
        }
    })
}
<commit_msg>Fix handling of element names<commit_after>extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use quote::{Tokens, ToTokens};
use syn::*;

#[proc_macro_derive(ColladaElement, attributes(name, attribute, child, text_data))]
pub fn derive(input: TokenStream) -> TokenStream {
    // Parse the string representation.
    let ast = syn::parse_derive_input(&input.to_string()).unwrap();

    // Build the impl.
    match generate_impl(ast) {
        Ok(gen) => {
            gen.parse().unwrap()
        }
        Err(error) => { panic!("{}", error) }
    }
}

fn process_derive_input(input: DeriveInput) -> Result<ElementConfiguration, String> {
    let struct_ident = input.ident;

    // Process the top-level attributes on the type to find the `#[name = "foo"]` attribute.
    // -------------------------------------------------------------------------------------
    let element_name = {
        let mut element_name = None;

        for attribute in input.attrs {
            match attribute.value {
                MetaItem::NameValue(attr_name, Lit::Str(value, _)) => {
                    if attr_name == "name" {
                        element_name = Some(value);
                    }
                }

                _ => {}
            }
        }

        element_name.ok_or(r#"Type must have `#[name = "..."]` attribute when using `#[derive(ColladaElement)]`"#)?
    };

    // Process the body of the type and gather information about attributes and children.
    // ----------------------------------------------------------------------------------
    let mut children = Vec::new();
    let mut attributes = Vec::new();

    let fields = match input.body {
        Body::Enum(_) => { return Err("`#[derive(ColladaElement)]` does not support enum types")?; }

        Body::Struct(VariantData::Struct(fields)) => { fields }

        Body::Struct(VariantData::Tuple(_)) => { return Err("`#[derive(ColladaElement)]` does not support tuple structs")?; }

        Body::Struct(VariantData::Unit) => { Vec::new() }
    };

    for field in fields {
        // We only support struct-structs, so all fields will have an ident.
        let member_name = field.ident.unwrap();

        // Determine the data type and occurrences for the member.
        let path = match field.ty.clone() {
            Ty::Path(None, path) => { path }
            _ => { return Err("`#[derive(ColladaElement)]` doesn't support this member type")?; }
        };

        // Determine the number of occurrences based on the declared type:
        //
        // - `Option<T>` is optional with inner type `T`.
        // - `Vec<T>` is repeating with inner type `T`.
        // - Everything else is required with inner type as declared.
        let segment = path.segments.last().expect("Somehow got an empty path ?_?");

        // We only support angle bracket parameters (because we're only looking for `Option<T>`
        // and `Vec<T>`), so extract the parameter data and throw away all others.
        let parameter_data = match segment.parameters {
            PathParameters::AngleBracketed(ref param) => { param }
            _ => { return Err("Round brace function parameters are not supported")?; }
        };

        // Depending on the number of parameters (0 or 1) we determine the occurrences and the
        // type of the actual data.
        let (occurrences, inner_type) = if parameter_data.types.len() == 0 {
            // No type parameters, so we're not looking at `Option<T>` or `Vec<T>`. That means the
            // child is required and that the field's type is the type of the child data.
            (ChildOccurrences::Required, field.ty)
        } else {
            // There's 1 type parameter, so determine if we're looking at an `Option<T>`, which
            // means optional occurrences of a `T`, or a `Vec<T>`, which means optional many
            // occurrences of `T`.
            let inner_type = parameter_data.types[0].clone();
            match segment.ident.as_ref() {
                "Option" => { (ChildOccurrences::Optional, inner_type) }
                "Vec" => { (ChildOccurrences::OptionalMany, inner_type) }
                _ => { return Err("Unexpected child type with parameters, only `Vec<T>` and `Option<T>` are allowed to have type parameters")?; }
            }
        };

        // Determine the data type of the inner type, e.g. if it's `String` or another ColladaElement.
        let data_type = match inner_type {
            Ty::Path(None, ref path) => {
                let segment = path.segments.last().expect("Somehow got an empty path ?_?");
                if segment.ident.as_ref() == "String" {
                    DataType::TextData(inner_type.clone())
                } else {
                    // Check for a `#[text_data]` attribute.
                    let mut has_text_data_attr = false;
                    for attribute in &field.attrs {
                        if attribute.name() == "text_data" {
                            has_text_data_attr = true;
                        }
                    }

                    if has_text_data_attr {
                        DataType::TextData(inner_type.clone())
                    } else {
                        DataType::ColladaElement(inner_type.clone())
                    }
                }
            },

            _ => { return Err("`#[derive(ColladaElement)]` doesn't support this member type")?; }
        };

        // Determine whether we're looking at a child or an attribute based on whether the member
        // has a `#[child]` or an `#[attribute]` attribute.
        for attribute in field.attrs {
            match attribute.name() {
                "child" => {
                    children.push(Child {
                        member_name: member_name.clone(),
                        element_name: member_name.to_string(),
                        occurrences: occurrences,
                        data_type: data_type,
                    });
                    break;
                }

                "attribute" => {
                    let occurrences = match occurrences {
                        ChildOccurrences::Optional => AttributeOccurrences::Optional,
                        ChildOccurrences::Required => AttributeOccurrences::Required,

                        ChildOccurrences::OptionalMany | ChildOccurrences::RequiredMany => {
                            return Err("Attribute may not be repeating, meaning it may not be of type `Vec<T>`".into());
                        }
                    };

                    attributes.push(Attribute {
                        member_name: member_name.clone(),
                        attrib_name: member_name.to_string(),
                        occurrences: occurrences,
                        ty: inner_type,
                    });
                    break;
                }

                _ => {}
            }
        }
    }

    Ok(ElementConfiguration {
        struct_ident: struct_ident,
        element_name: element_name,
        attributes: attributes,
        children: children,
    })
}

struct ElementConfiguration {
    struct_ident: Ident,
    element_name: String,
    attributes: Vec<Attribute>,
    children: Vec<Child>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum AttributeOccurrences {
    Optional,
    Required,
}

struct Attribute {
    member_name: Ident,
    attrib_name: String,
    occurrences: AttributeOccurrences,
    ty: Ty,
}

enum DataType {
    TextData(Ty),
    ColladaElement(Ty),
}

struct Child {
    member_name: Ident,
    element_name: String,
    occurrences: ChildOccurrences,
    data_type: DataType,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ChildOccurrences {
    Optional,
    Required,
    OptionalMany,
    RequiredMany,
}

impl ToTokens for ChildOccurrences {
    fn to_tokens(&self, tokens: &mut Tokens) {
        match *self {
            ChildOccurrences::Optional => { tokens.append("Optional"); }

            ChildOccurrences::Required => { tokens.append("Required"); }

            ChildOccurrences::OptionalMany => { tokens.append("Many"); }

            ChildOccurrences::RequiredMany => { tokens.append("RequiredMany"); }
        }
    }
}

fn generate_impl(derive_input: DeriveInput) -> Result<quote::Tokens, String> {
    let ElementConfiguration { struct_ident, element_name, attributes, children } = process_derive_input(derive_input)?;

    // Generate declarations for the member variables of the struct.
    // -------------------------------------------------------------
    let member_decls = {
        let attribs = attributes.iter()
            .map(|attrib| {
                let ident = &attrib.member_name;
                quote! { let mut #ident = None; }
            });
        let childs = children.iter()
            .map(|child| {
                let &Child { ref member_name, occurrences, .. } = child;
                match occurrences {
                    ChildOccurrences::Optional | ChildOccurrences::Required => {
                        quote! { let mut #member_name = None; }
                    }

                    ChildOccurrences::OptionalMany | ChildOccurrences::RequiredMany => {
                        quote! { let mut #member_name = Vec::new(); }
                    }
                }
            });

        quote! {
            #( #attribs )*
            #( #childs )*
        }
    };

    // Generate code for parsing attributes.
    // -------------------------------------
    let attributes_impl = if attributes.len() != 0 {
        let matches = attributes.iter()
            .map(|attrib| {
                let &Attribute { ref member_name, ref attrib_name, ref ty, .. } = attrib;
                quote! {
                    #attrib_name => {
                        let result = #ty::from_str(&*attribute.value)
                            .map_err(|error| Error {
                                position: reader.position(),
                                kind: error.into(),
                            })?;
                        #member_name = Some(result);
                    }
                }
            });

        let attrib_names = attributes.iter()
            .map(|attrib| { &*attrib.attrib_name });

        let required_attribs = attributes.iter()
            .filter(|attrib| { attrib.occurrences == AttributeOccurrences::Required })
            .map(|attrib| {
                let &Attribute { ref member_name, ref attrib_name, .. } = attrib;
                quote! {
                    let #member_name = #member_name.ok_or(Error {
                        position: reader.position(),
                        kind: ErrorKind::MissingAttribute {
                            element: #element_name,
                            attribute: #attrib_name,
                        },
                    })?;
                }
            });

        quote! {
            for attribute in attributes {
                match &*attribute.name.local_name {
                    #( #matches )*

                    attrib_name @ _ => {
                        return Err(Error {
                            position: reader.position(),
                            kind: ErrorKind::UnexpectedAttribute {
                                element: #element_name,
                                attribute: attrib_name.into(),
                                expected: vec![ #( #attrib_names ),* ],
                            },
                        })
                    }
                }
            }

            #( #required_attribs )*
        }
    } else {
        quote! {
            utils::verify_attributes(reader, #element_name, attributes)?;
        }
    };

    // Generate code for parsing children.
    // -----------------------------------
    let children_impl = {
        let decls = children.iter()
            .map(|child| {
                let &Child { ref member_name, ref element_name, occurrences, ref data_type } = child;

                let name = match *data_type {
                    DataType::TextData(_) => {
                        quote! {
                            #element_name
                        }
                    }

                    DataType::ColladaElement(ref ty) => {
                        quote! {
                            #ty::name()
                        }
                    }
                };

                let handle_result = match (occurrences, data_type) {
                    (ChildOccurrences::Optional, &DataType::TextData(_)) => {
                        quote! {
                            utils::verify_attributes(reader, #element_name, attributes)?;
                            #member_name = utils::optional_text_contents(reader, #element_name)?;
                        }
                    }

                    (ChildOccurrences::Required, &DataType::TextData(_)) => {
                        quote! {
                            utils::verify_attributes(reader, #element_name, attributes)?;
                            let result = utils::required_text_contents(reader, #element_name)?;
                            #member_name = Some(result);
                        }
                    }

                    (ChildOccurrences::OptionalMany, &DataType::TextData(_)) => {
                        quote! {
                            utils::verify_attributes(reader, #element_name, attributes)?;
                            if let Some(result) = utils::optional_text_contents(reader, #element_name)? {
                                #member_name.push(result.parse()?);
                            }
                        }
                    }

                    (ChildOccurrences::RequiredMany, &DataType::TextData(_)) => {
                        quote! {
                            utils::verify_attributes(reader, #element_name, attributes)?;
                            if let Some(result) = utils::optional_text_contents(reader, #element_name)? {
                                #member_name.push(result.parse()?);
                            }
                        }
                    }

                    (ChildOccurrences::Optional, &DataType::ColladaElement(ref ident)) => {
                        quote! {
                            let result = #ident::parse_element(reader, attributes)?;
                            #member_name = Some(result);
                        }
                    }

                    (ChildOccurrences::Required, &DataType::ColladaElement(ref ident)) => {
                        quote! {
                            let result = #ident::parse_element(reader, attributes)?;
                            #member_name = Some(result);
                        }
                    }

                    (ChildOccurrences::OptionalMany, &DataType::ColladaElement(ref ident)) => {
                        quote! {
                            let result = #ident::parse_element(reader, attributes)?;
                            #member_name.push(result);
                        }
                    }

                    (ChildOccurrences::RequiredMany, &DataType::ColladaElement(ref ident)) => {
                        quote! {
                            let result = #ident::parse_element(reader, attributes)?;
                            #member_name.push(result);
                        }
                    }
                };

                quote! {
                    ChildConfiguration {
                        name: #name,
                        occurrences: #occurrences,

                        action: &mut |reader, attributes| {
                            #handle_result
                            Ok(())
                        },
                    }
                }
            });

        let required_childs = children.iter()
            .filter_map(|child| {
                let &Child { ref member_name, occurrences, .. } = child;
                if occurrences == ChildOccurrences::Required {
                    Some(quote! {
                        let #member_name = #member_name.expect("Required child was `None`");
                    })
                } else {
                    None
                }
            });

        quote! {
            ElementConfiguration {
                name: #element_name,
                children: &mut [
                    #( #decls ),*
                ],
            }.parse_children(reader)?;

            #( #required_childs )*
        }
    };

    // Generate code to construct final result.
    // ----------------------------------------
    let result_decl = {
        let attribs = attributes.iter()
            .map(|attrib| {
                let ident = &attrib.member_name;
                quote! { #ident: #ident }
            });
        let childs = children.iter()
            .map(|child| {
                let ident = &child.member_name;
                quote! { #ident: #ident }
            });

        quote! {
            Ok(#struct_ident {
                #( #attribs ),*
                #( #childs ),*
            })
        }
    };

    // Put all the pieces together.
    // ----------------------------
    Ok(quote! {
        impl ::utils::ColladaElement for #struct_ident {
            #[allow(unused_imports)]
            fn parse_element<R: ::std::io::Read>(
                reader: &mut ::xml::reader::EventReader<R>,
                attributes: Vec<::xml::attribute::OwnedAttribute>
            ) -> Result<Self> {
                use std::str::FromStr;
                use utils::*;

                #member_decls

                #attributes_impl

                #children_impl

                #result_decl
            }

            fn name() -> &'static str {
                #element_name
            }
        }
    })
}
<|endoftext|>


<commit_before>//
// OpenAOE: An open source reimplementation of Age of Empires (1997)
// Copyright (c) 2016 Kevin Fuller
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

use error::*;

use io_tools::*;

use std::io::prelude::*;

#[derive(Default, Debug)]
pub struct AgeEffect {
    type_id: i8,
    effect_a: i16,
    effect_b: i16,
    effect_c: i16,
    effect_d: f32,
}

#[derive(Default, Debug)]
pub struct Age {
    name: String,
    effects: Vec<AgeEffect>,
}

pub fn read_ages<R: Read + Seek>(stream: &mut R) -> EmpiresDbResult<Vec<Age>> {
    let age_count = try!(stream.read_u32()) as usize;
    stream.read_array(age_count, |c| read_age(c))
}

pub fn read_age<R: Read + Seek>(stream: &mut R) -> EmpiresDbResult<Age> {
    let mut age: Age = Default::default();
    age.name = try!(stream.read_sized_str(31));

    let effect_count = try!(stream.read_u16()) as usize;
    age.effects = try!(stream.read_array(effect_count, |c| read_age_effect(c)));
    Ok(age)
}

fn read_age_effect<R: Read + Seek>(stream: &mut R) -> EmpiresDbResult<AgeEffect> {
    let mut effect: AgeEffect = Default::default();
    effect.type_id = try!(stream.read_i8());
    effect.effect_a = try!(stream.read_i16());
    effect.effect_b = try!(stream.read_i16());
    effect.effect_c = try!(stream.read_i16());
    effect.effect_d = try!(stream.read_f32());
    Ok(effect)
}
<commit_msg>Implement better age deserialization<commit_after>//
// OpenAOE: An open source reimplementation of Age of Empires (1997)
// Copyright (c) 2016 Kevin Fuller
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

use empires::resource::*;
use error::*;

use io_tools::*;

use std::io::prelude::*;

#[derive(Debug)]
pub enum AgeEffectValue {
    SetTo(f32),
    Add(f32),
    MultiplyBy(f32),
}

#[derive(Debug)]
pub enum AgeEffect {
    UnitAttribute {
        target_unit_id: i16,
        target_unit_class_id: i16,
        attribute_id: i16,
        effect: AgeEffectValue,
    },

    CivHeader {
        target_civ_header_id: i16,
        effect: AgeEffectValue,
    },

    SetUnitEnabled {
        target_unit_id: i16,
        enabled: bool,
    },

    UpgradeUnit {
        source_unit_id: i16,
        target_unit_id: i16,
    },

    ResearchCost {
        research_id: i16,
        resource_type: ResourceType,
        effect: AgeEffectValue,
    },

    DisableResearch {
        research_id: i16,
    },

    GainResearch {
        research_id: i16,
    },

    Unknown {
        type_id: i8,
        param_a: i16,
        param_b: i16,
        param_c: i16,
        param_d: f32,
    },
}

impl Default for AgeEffect {
    fn default() -> AgeEffect {
        AgeEffect::Unknown {
            type_id: -1,
            param_a: -1,
            param_b: -1,
            param_c: -1,
            param_d: -1f32,
        }
    }
}

#[derive(Default, Debug)]
pub struct Age {
    name: String,
    effects: Vec<AgeEffect>,
}

pub fn read_ages<R: Read + Seek>(stream: &mut R) -> EmpiresDbResult<Vec<Age>> {
    let age_count = try!(stream.read_u32()) as usize;
    stream.read_array(age_count, |c| read_age(c))
}

pub fn read_age<R: Read + Seek>(stream: &mut R) -> EmpiresDbResult<Age> {
    let mut age: Age = Default::default();
    age.name = try!(stream.read_sized_str(31));

    let effect_count = try!(stream.read_u16()) as usize;
    age.effects = try!(stream.read_array(effect_count, |c| read_age_effect(c)));
    Ok(age)
}

fn read_age_effect<R: Read + Seek>(stream: &mut R) -> EmpiresDbResult<AgeEffect> {
    let type_id = try!(stream.read_i8());
    let param_a = try!(stream.read_i16());
    let param_b = try!(stream.read_i16());
    let param_c = try!(stream.read_i16());
    let param_d = try!(stream.read_f32());

    use self::AgeEffect::*;
    use self::AgeEffectValue::*;
    let result = match type_id {
        0 | 4 | 5 => UnitAttribute {
            target_unit_id: param_a,
            target_unit_class_id: param_b,
            attribute_id: param_c,
            effect: match type_id {
                0 => SetTo(param_d),
                4 => Add(param_d),
                _ => MultiplyBy(param_d),
            },
        },

        1 if param_b == 0 || param_b == 1 => CivHeader {
            target_civ_header_id: param_a,
            effect: match param_b {
                0 => SetTo(param_d),
                _ => Add(param_d),
            }
        },

        6 => CivHeader {
            target_civ_header_id: param_a,
            effect: MultiplyBy(param_d),
        },

        2 => SetUnitEnabled {
            target_unit_id: param_a,
            enabled: param_b == 1,
        },

        3 => UpgradeUnit {
            source_unit_id: param_a,
            target_unit_id: param_b,
        },

        101 if param_c == 0 || param_c == 1 => ResearchCost {
            research_id: param_a,
            resource_type: ResourceType::from_i16(param_b),
            effect: match param_c {
                0 => SetTo(param_d),
                _ => Add(param_d),
            }
        },

        102 => DisableResearch {
            research_id: param_d as i16,
        },

        103 => GainResearch {
            research_id: param_a,
        },

        _ => Unknown {
            type_id: type_id,
            param_a: param_a,
            param_b: param_b,
            param_c: param_c,
            param_d: param_d,
        }
    };

    Ok(result)
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::fmt::{self, Write};
use std::str::FromStr;

#[derive(Debug)]
struct InvalidGameId;

#[derive(Debug, Clone, Eq, PartialEq)]
struct GameId(u64);

impl TryFrom<u64> for GameId {
    type Error = InvalidGameId;

    fn try_from(n: u64) -> Result<Self, Self::Error> {
        if n < 62u64.pow(8) {
            Ok(GameId(n))
        } else {
            Err(InvalidGameId)
        }
    }
}

impl FromStr for GameId {
    type Err = InvalidGameId;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if dbg!(s).len() != 8 {
            return Err(InvalidGameId);
        }

        let mut n = 0;
        for c in s.bytes().rev() {
            n = match c {
                b'0'..=b'9' => c - b'0',
                b'A'..=b'Z' => c - b'A' + 10,
                b'a'..=b'z' => c - b'a' + 10 + 26,
                _ => return Err(InvalidGameId),
            } as u64 + n * 62;
        }

        Ok(GameId(n))
    }
}

impl fmt::Display for GameId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut n = self.0;
        for _ in 0..8 {
            let rem = n % 62;
            f.write_char(char::from(if rem >= 10 + 26 {
                (rem - (10 + 26)) as u8 + b'a'
            } else if rem >= 10 {
                (rem - 10) as u8 + b'A'
            } else {
                rem as u8 + b'0'
            }))?;
            n /= 62;
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use quickcheck::{Arbitrary, Gen, quickcheck};
    use super::*;

    impl Arbitrary for GameId {
        fn arbitrary(g: &mut Gen) -> Self {
            GameId(u64::arbitrary(g) % 62u64.pow(8))
        }
    }

    quickcheck! {
        fn game_id_roundtrip(game_id: GameId) -> bool {
            GameId::from_str(&game_id.to_string()).unwrap() == game_id
        }
    }
}
<commit_msg>read and write game id from byte stream<commit_after>use std::fmt::{self, Write as _};
use std::str::FromStr;
use std::io;
use std::io::{Read, Write};
use byteorder::{LittleEndian, ReadBytesExt as _, WriteBytesExt as _};

#[derive(Debug)]
struct InvalidGameId;

#[derive(Debug, Clone, Eq, PartialEq)]
struct GameId(u64);

impl GameId {
    fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_u48::<LittleEndian>(self.0)
    }

    fn read<R: Read>(&self, reader: &mut R) -> io::Result<GameId> {
        let n = reader.read_u48::<LittleEndian>()?;
        if n < 62u64.pow(8) {
            Ok(GameId(n))
        } else {
            Err(io::ErrorKind::InvalidData.into())
        }
    }
}

impl FromStr for GameId {
    type Err = InvalidGameId;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if dbg!(s).len() != 8 {
            return Err(InvalidGameId);
        }

        let mut n = 0;
        for c in s.bytes().rev() {
            n = match c {
                b'0'..=b'9' => c - b'0',
                b'A'..=b'Z' => c - b'A' + 10,
                b'a'..=b'z' => c - b'a' + 10 + 26,
                _ => return Err(InvalidGameId),
            } as u64 + n * 62;
        }

        Ok(GameId(n))
    }
}

impl fmt::Display for GameId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut n = self.0;
        for _ in 0..8 {
            let rem = n % 62;
            f.write_char(char::from(if rem >= 10 + 26 {
                (rem - (10 + 26)) as u8 + b'a'
            } else if rem >= 10 {
                (rem - 10) as u8 + b'A'
            } else {
                rem as u8 + b'0'
            }))?;
            n /= 62;
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use quickcheck::{Arbitrary, Gen, quickcheck};
    use super::*;

    impl Arbitrary for GameId {
        fn arbitrary(g: &mut Gen) -> Self {
            GameId(u64::arbitrary(g) % 62u64.pow(8))
        }
    }

    quickcheck! {
        fn game_id_roundtrip(game_id: GameId) -> bool {
            GameId::from_str(&game_id.to_string()).unwrap() == game_id
        }
    }
}
<|endoftext|>


<commit_before>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn init() -> Model {
        unimplemented!();
    }
}

pub enum Turn {
    White,
    Black,
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Tried to get field on removed hex: {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        unimplemented!();
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        unimplemented!();
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        let x = coord.x + 2;
        let y = coord.y + 2;
        &self.board[x as usize][y as usize]
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        coord
            .get_neighbors()
            .iter()
            .filter_map(|&(_, c)| match *self.get_hex(&c) {
                Some(_) => Some(c),
                None => None,
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for (i, neighbor) in coord.get_neighbors() {
            if self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
        }
        neighbors
    }
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        unimplemented!();
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        unimplemented!();
    }
}

#[derive(Debug)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return a Vec of tuples so that get_hex_field_neighbors and is_hex_removable know which
    // neighbors are on which side of the hex. They need to know this for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable if it is attached to the board by 3 or less
    //                       *adjacent* sides
    fn get_neighbors(&self) -> Vec<(u32, HexCoord)> {
        let mut neighbors = vec![];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors.push((0, HexCoord::new(self.x, self.y + 1)));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors.push((1, HexCoord::new(self.x + 1, self.y)));
        }
        if self.x < 2 && self.y > -2 {
            neighbors.push((2, HexCoord::new(self.x + 1, self.y - 1)));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors.push((3, HexCoord::new(self.x, self.y - 1)));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors.push((4, HexCoord::new(self.x - 1, self.y)));
        }
        if self.x > -2 && self.y < 2 {
            neighbors.push((5, HexCoord::new(self.x - 1, self.y + 1)));
        }

        neighbors
    }
}
<commit_msg>Implement Board::new and Model::init<commit_after>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn init() -> Model {
        Model {
            board: Board::new(),
            turn: Turn::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
        }
    }
}

pub enum Turn {
    White,
    Black,
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let board = Board {
            board: [[Some([Field::Empty; 6]); 5]; 5],
        };

        let piece_locations = [

            // (0, 0) is the only empty hex
            (HexCoord::new(-2,  2), [0, 4]),
            (HexCoord::new(-2,  1), [0, 3]),
            (HexCoord::new(-2,  0), [3, 5]),
            (HexCoord::new(-1,  2), [1, 4]),
            (HexCoord::new(-1,  1), [0, 4]),
            (HexCoord::new(-1,  0), [3, 5]),
            (HexCoord::new(-1, -1), [2, 5]),
            (HexCoord::new( 0,  2), [1, 5]),
            (HexCoord::new( 0,  1), [1, 5]),
            (HexCoord::new( 0, -1), [2, 4]),
            (HexCoord::new( 0, -2), [2, 4]),
            (HexCoord::new( 1,  1), [2, 5]),
            (HexCoord::new( 1,  0), [0, 2]),
            (HexCoord::new( 1, -1), [1, 3]),
            (HexCoord::new( 1, -2), [1, 4]),
            (HexCoord::new( 2,  0), [0, 2]),
            (HexCoord::new( 2, -1), [0, 3]),
            (HexCoord::new( 2, -2), [1, 3]),
        ];

        for &(coord, fields) in &piece_locations {
            let mut hex = board.get_hex(&coord).unwrap();
            hex[fields[0]] = Field::Piece;
            hex[fields[1]] = Field::Piece;
        }

        board
    }

    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Tried to get field on removed hex: {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        unimplemented!();
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        unimplemented!();
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        let x = coord.x + 2;
        let y = coord.y + 2;
        &self.board[x as usize][y as usize]
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        coord
            .get_neighbors()
            .iter()
            .filter_map(|&(_, c)| match *self.get_hex(&c) {
                Some(_) => Some(c),
                None => None,
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for (i, neighbor) in coord.get_neighbors() {
            if self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
        }
        neighbors
    }
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        unimplemented!();
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        unimplemented!();
    }
}

#[derive(Debug)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return a Vec of tuples so that get_hex_field_neighbors and is_hex_removable know which
    // neighbors are on which side of the hex. They need to know this for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable if it is attached to the board by 3 or less
    //                       *adjacent* sides
    fn get_neighbors(&self) -> Vec<(u32, HexCoord)> {
        let mut neighbors = vec![];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors.push((0, HexCoord::new(self.x, self.y + 1)));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors.push((1, HexCoord::new(self.x + 1, self.y)));
        }
        if self.x < 2 && self.y > -2 {
            neighbors.push((2, HexCoord::new(self.x + 1, self.y - 1)));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors.push((3, HexCoord::new(self.x, self.y - 1)));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors.push((4, HexCoord::new(self.x - 1, self.y)));
        }
        if self.x > -2 && self.y < 2 {
            neighbors.push((5, HexCoord::new(self.x - 1, self.y + 1)));
        }

        neighbors
    }
}
<|endoftext|>


<commit_before>use approxeq::ApproxEq;
use num_traits::Float;
use trig::Trig;
use {TypedRotation3D, TypedTransform3D, TypedVector3D, UnknownUnit};

/// A rigid transformation. All lengths are preserved under such a transformation.
///
///
/// Internally, this is a rotation and a translation, with the rotation
/// applied first (i.e. `Translation * Rotation`)
///
/// This can be more efficient to use over full matrices, especially if you
/// have to deal with the decomposed quantities often.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(C)]
pub struct TypedRigidTransform3D<T, Src, Dst> {
    pub rotation: TypedRotation3D<T, Src, Dst>,
    pub translation: TypedVector3D<T, Dst>,
}

pub type RigidTransform3D<T> = TypedRigidTransform3D<T, UnknownUnit, UnknownUnit>;

impl<T: Float + ApproxEq<T>, Src, Dst> TypedRigidTransform3D<T, Src, Dst> {
    /// Construct a new rigid transformation, where the `rotation` applies first
    #[inline]
    pub fn new(rotation: TypedRotation3D<T, Src, Dst>, translation: TypedVector3D<T, Dst>) -> Self {
        Self {
            rotation,
            translation,
        }
    }

    /// Construct an identity transform
    #[inline]
    pub fn identity() -> Self {
        Self {
            rotation: TypedRotation3D::identity(),
            translation: TypedVector3D::zero(),
        }
    }

    /// Construct a new rigid transformation, where the `translation` applies first
    #[inline]
    pub fn new_from_reversed(
        translation: TypedVector3D<T, Src>,
        rotation: TypedRotation3D<T, Src, Dst>,
    ) -> Self {
        // R * T
        //   = R * T * (R^-1 * R)
        //   = (R * T * R^-1) * R
        //   = T' * R
        //
        // T' = (R * T * R^-1) is also a translation matrix
        // It is equivalent to the translation matrix obtained by rotating the
        // translation by R

        let translation = rotation.rotate_vector3d(&translation);
        Self {
            rotation,
            translation,
        }
    }

    #[inline]
    pub fn from_rotation(rotation: TypedRotation3D<T, Src, Dst>) -> Self {
        Self {
            rotation,
            translation: TypedVector3D::zero(),
        }
    }

    #[inline]
    pub fn from_translation(translation: TypedVector3D<T, Dst>) -> Self {
        Self {
            translation,
            rotation: TypedRotation3D::identity(),
        }
    }

    /// Decompose this into a translation and an rotation to be applied in the opposite order
    ///
    /// i.e., the translation is applied _first_
    #[inline]
    pub fn decompose_reversed(&self) -> (TypedVector3D<T, Src>, TypedRotation3D<T, Src, Dst>) {
        // self = T * R
        //      = R * R^-1 * T * R
        //      = R * (R^-1 * T * R)
        //      = R * T'
        //
        // T' = (R^-1 * T * R) is T rotated by R^-1

        let translation = self.rotation.inverse().rotate_vector3d(&self.translation);
        (translation, self.rotation)
    }

    /// Returns the multiplication of the two transforms such that
    /// other's transformation applies after self's transformation.
    ///
    /// i.e., this produces `other * self`, postmultiplying self to other
    #[inline]
    pub fn post_mul<Dst2>(
        &self,
        other: &TypedRigidTransform3D<T, Dst, Dst2>,
    ) -> TypedRigidTransform3D<T, Src, Dst2> {
        // self = T1 * R1
        // other = T2 * R2
        // result = T2 * R2 * T1 * R1
        //        = T2 * R2 * R1 * R1^-1 * T1 * R1
        //        = T2 * R2 * R1 * (R1^-1 * T1 * R1)
        //        = T2 * R' * T'
        //        = T2 * R' * T' * R'^-1 * R'
        //        = T2 * (R' * T' * R'^-1) * R'
        //        = T2 * T'' * R'
        //        = T'' * R'
        //
        // (R1^-1 * T1 * R1) = T' = T1 rotated by R1^-1
        // R2 * R1  = R'
        // (R' * T' * R'^-1) = T'' = T' rotated by R'
        // T2 * T'' = T''' = T2 + T'

        let t_prime = self
            .rotation
            .inverse()
            .rotate_vector3d(&self.translation);
        let r_prime = self.rotation.post_rotate(&other.rotation);
        let t_prime2 = r_prime.rotate_vector3d(&t_prime);
        let t_prime3 = t_prime2 + other.translation;
        TypedRigidTransform3D {
            rotation: r_prime,
            translation: t_prime3,
        }
    }

    /// Returns the multiplication of the two transforms such that
    /// self's transformation applies after other's transformation.
    ///
    /// i.e., this produces `self * other`, premultiplying self to other
    #[inline]
    pub fn pre_mul<Src2>(
        &self,
        other: &TypedRigidTransform3D<T, Src2, Src>,
    ) -> TypedRigidTransform3D<T, Src2, Dst> {
        other.post_mul(&self)
    }

    /// Inverts the transformation
    #[inline]
    pub fn inverse(&self) -> TypedRigidTransform3D<T, Dst, Src> {
        // result = (self)^-1
        //        = (T * R)^-1
        //        = R^-1 * T^-1
        //        = R^-1 * T^-1 * R * R^-1
        //        = (R^-1 * T^-1 * R) * R^-1
        //        = T' * R'
        //
        // T' = (R^-1 * T^-1 * R) = (-T) rotated by R^-1
        // R' = R^-1
        //
        // An easier way of writing this is to use new_from_reversed() with R^-1 and T^-1

        TypedRigidTransform3D::new_from_reversed(
            -self.translation,
            self.rotation.inverse(),
        )
    }

    pub fn to_transform(&self) -> TypedTransform3D<T, Src, Dst>
    where
        T: Trig,
    {
        self.translation
            .to_transform()
            .pre_mul(&self.rotation.to_transform())
    }
}

impl<T: Float + ApproxEq<T>, Src, Dst> From<TypedRotation3D<T, Src, Dst>>
    for TypedRigidTransform3D<T, Src, Dst>
{
    fn from(rot: TypedRotation3D<T, Src, Dst>) -> Self {
        Self::from_rotation(rot)
    }
}

impl<T: Float + ApproxEq<T>, Src, Dst> From<TypedVector3D<T, Dst>>
    for TypedRigidTransform3D<T, Src, Dst>
{
    fn from(t: TypedVector3D<T, Dst>) -> Self {
        Self::from_translation(t)
    }
}

#[cfg(test)]
mod test {
    use super::RigidTransform3D;
    use {Rotation3D, TypedTransform3D, Vector3D};

    #[test]
    fn test_rigid_construction() {
        let translation = Vector3D::new(12.1, 17.8, -5.5);
        let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);

        let rigid = RigidTransform3D::new(rotation, translation);
        assert!(rigid
            .to_transform()
            .approx_eq(&translation.to_transform().pre_mul(&rotation.to_transform())));

        let rigid = RigidTransform3D::new_from_reversed(translation, rotation);
        assert!(rigid.to_transform().approx_eq(
            &translation
                .to_transform()
                .post_mul(&rotation.to_transform())
        ));
    }

    #[test]
    fn test_rigid_decomposition() {
        let translation = Vector3D::new(12.1, 17.8, -5.5);
        let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);

        let rigid = RigidTransform3D::new(rotation, translation);
        let (t2, r2) = rigid.decompose_reversed();
        assert!(rigid
            .to_transform()
            .approx_eq(&t2.to_transform().post_mul(&r2.to_transform())));
    }

    #[test]
    fn test_rigid_inverse() {
        let translation = Vector3D::new(12.1, 17.8, -5.5);
        let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);

        let rigid = RigidTransform3D::new(rotation, translation);
        let inverse = rigid.inverse();
        assert!(rigid
            .post_mul(&inverse)
            .to_transform()
            .approx_eq(&TypedTransform3D::identity()));
        assert!(inverse
            .to_transform()
            .approx_eq(&rigid.to_transform().inverse().unwrap()));
    }

    #[test]
    fn test_rigid_multiply() {
        let translation = Vector3D::new(12.1, 17.8, -5.5);
        let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);
        let translation2 = Vector3D::new(9.3, -3.9, 1.1);
        let rotation2 = Rotation3D::unit_quaternion(0.1, 0.2, 0.3, -0.4);
        let rigid = RigidTransform3D::new(rotation, translation);
        let rigid2 = RigidTransform3D::new(rotation2, translation2);

        assert!(rigid
            .post_mul(&rigid2)
            .to_transform()
            .approx_eq(&rigid.to_transform().post_mul(&rigid2.to_transform())));
        assert!(rigid
            .pre_mul(&rigid2)
            .to_transform()
            .approx_eq(&rigid.to_transform().pre_mul(&rigid2.to_transform())));
    }
}
<commit_msg>Swap matrix math to use row-vector notation<commit_after>use approxeq::ApproxEq;
use num_traits::Float;
use trig::Trig;
use {TypedRotation3D, TypedTransform3D, TypedVector3D, UnknownUnit};

/// A rigid transformation. All lengths are preserved under such a transformation.
///
///
/// Internally, this is a rotation and a translation, with the rotation
/// applied first (i.e. `Rotation * Translation`, in row-vector notation)
///
/// This can be more efficient to use over full matrices, especially if you
/// have to deal with the decomposed quantities often.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(C)]
pub struct TypedRigidTransform3D<T, Src, Dst> {
    pub rotation: TypedRotation3D<T, Src, Dst>,
    pub translation: TypedVector3D<T, Dst>,
}

pub type RigidTransform3D<T> = TypedRigidTransform3D<T, UnknownUnit, UnknownUnit>;

// All matrix multiplication in this file is in row-vector notation,
// i.e. a vector `v` is transformed with `v * T`, and if you want to apply `T1`
// before `T2` you use `T1 * T2`

impl<T: Float + ApproxEq<T>, Src, Dst> TypedRigidTransform3D<T, Src, Dst> {
    /// Construct a new rigid transformation, where the `rotation` applies first
    #[inline]
    pub fn new(rotation: TypedRotation3D<T, Src, Dst>, translation: TypedVector3D<T, Dst>) -> Self {
        Self {
            rotation,
            translation,
        }
    }

    /// Construct an identity transform
    #[inline]
    pub fn identity() -> Self {
        Self {
            rotation: TypedRotation3D::identity(),
            translation: TypedVector3D::zero(),
        }
    }

    /// Construct a new rigid transformation, where the `translation` applies first
    #[inline]
    pub fn new_from_reversed(
        translation: TypedVector3D<T, Src>,
        rotation: TypedRotation3D<T, Src, Dst>,
    ) -> Self {
        // T * R
        //   = (R * R^-1) * T * R
        //   = R * (R^-1 * T * R)
        //   = R * T'
        //
        // T' = (R^-1 * T * R) is also a translation matrix
        // It is equivalent to the translation matrix obtained by rotating the
        // translation by R

        let translation = rotation.rotate_vector3d(&translation);
        Self {
            rotation,
            translation,
        }
    }

    #[inline]
    pub fn from_rotation(rotation: TypedRotation3D<T, Src, Dst>) -> Self {
        Self {
            rotation,
            translation: TypedVector3D::zero(),
        }
    }

    #[inline]
    pub fn from_translation(translation: TypedVector3D<T, Dst>) -> Self {
        Self {
            translation,
            rotation: TypedRotation3D::identity(),
        }
    }

    /// Decompose this into a translation and an rotation to be applied in the opposite order
    ///
    /// i.e., the translation is applied _first_
    #[inline]
    pub fn decompose_reversed(&self) -> (TypedVector3D<T, Src>, TypedRotation3D<T, Src, Dst>) {
        // self = R * T
        //      = R * T * (R^-1 * R)
        //      = (R * T * R^-1) * R)
        //      = T' * R
        //
        // T' = (R^ * T * R^-1) is T rotated by R^-1

        let translation = self.rotation.inverse().rotate_vector3d(&self.translation);
        (translation, self.rotation)
    }

    /// Returns the multiplication of the two transforms such that
    /// other's transformation applies after self's transformation.
    ///
    /// i.e., this produces `self * other` in row-vector notation
    #[inline]
    pub fn post_mul<Dst2>(
        &self,
        other: &TypedRigidTransform3D<T, Dst, Dst2>,
    ) -> TypedRigidTransform3D<T, Src, Dst2> {
        // self = R1 * T1
        // other = R2 * T2
        // result = R1 * T1 * R2 * T2
        //        = R1 * T1 * (R1^-1 * R1) * R2 * T2
        //        = (R1 * T1 * R1^-1) * R1 * R2 * T2
        //        = T' * R' * T2
        //        = (R' * R'^-1) * T' * R' * T2
        //        = R' * (R'^-1 * T' * R') * T2
        //        = R' * T'' * T2
        //        = R' * T'''
        //
        // (R1 * T1 * R1^-1) = T' = T1 rotated by R1^-1
        // R1 * R2  = R'
        // (R'^-1 * T' * R') = T'' = T' rotated by R'
        // T'' * T2 = T''' = vector addition of translations T2 and T''

        let t_prime = self
            .rotation
            .inverse()
            .rotate_vector3d(&self.translation);
        let r_prime = self.rotation.post_rotate(&other.rotation);
        let t_prime2 = r_prime.rotate_vector3d(&t_prime);
        let t_prime3 = t_prime2 + other.translation;
        TypedRigidTransform3D {
            rotation: r_prime,
            translation: t_prime3,
        }
    }

    /// Returns the multiplication of the two transforms such that
    /// self's transformation applies after other's transformation.
    ///
    /// i.e., this produces `other * self` in row-vector notation
    #[inline]
    pub fn pre_mul<Src2>(
        &self,
        other: &TypedRigidTransform3D<T, Src2, Src>,
    ) -> TypedRigidTransform3D<T, Src2, Dst> {
        other.post_mul(&self)
    }

    /// Inverts the transformation
    #[inline]
    pub fn inverse(&self) -> TypedRigidTransform3D<T, Dst, Src> {
        // result = (self)^-1
        //        = (R * T)^-1
        //        = T^-1 * R^-1
        //        = (R^-1 * R) * T^-1 * R^-1
        //        = R^-1 * (R * T^-1 * R^-1)
        //        = R' * T'
        //
        // T' = (R * T^-1 * R^-1) = (-T) rotated by R^-1
        // R' = R^-1
        //
        // An easier way of writing this is to use new_from_reversed() with R^-1 and T^-1

        TypedRigidTransform3D::new_from_reversed(
            -self.translation,
            self.rotation.inverse(),
        )
    }

    pub fn to_transform(&self) -> TypedTransform3D<T, Src, Dst>
    where
        T: Trig,
    {
        self.translation
            .to_transform()
            .pre_mul(&self.rotation.to_transform())
    }
}

impl<T: Float + ApproxEq<T>, Src, Dst> From<TypedRotation3D<T, Src, Dst>>
    for TypedRigidTransform3D<T, Src, Dst>
{
    fn from(rot: TypedRotation3D<T, Src, Dst>) -> Self {
        Self::from_rotation(rot)
    }
}

impl<T: Float + ApproxEq<T>, Src, Dst> From<TypedVector3D<T, Dst>>
    for TypedRigidTransform3D<T, Src, Dst>
{
    fn from(t: TypedVector3D<T, Dst>) -> Self {
        Self::from_translation(t)
    }
}

#[cfg(test)]
mod test {
    use super::RigidTransform3D;
    use {Rotation3D, TypedTransform3D, Vector3D};

    #[test]
    fn test_rigid_construction() {
        let translation = Vector3D::new(12.1, 17.8, -5.5);
        let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);

        let rigid = RigidTransform3D::new(rotation, translation);
        assert!(rigid
            .to_transform()
            .approx_eq(&translation.to_transform().pre_mul(&rotation.to_transform())));

        let rigid = RigidTransform3D::new_from_reversed(translation, rotation);
        assert!(rigid.to_transform().approx_eq(
            &translation
                .to_transform()
                .post_mul(&rotation.to_transform())
        ));
    }

    #[test]
    fn test_rigid_decomposition() {
        let translation = Vector3D::new(12.1, 17.8, -5.5);
        let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);

        let rigid = RigidTransform3D::new(rotation, translation);
        let (t2, r2) = rigid.decompose_reversed();
        assert!(rigid
            .to_transform()
            .approx_eq(&t2.to_transform().post_mul(&r2.to_transform())));
    }

    #[test]
    fn test_rigid_inverse() {
        let translation = Vector3D::new(12.1, 17.8, -5.5);
        let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);

        let rigid = RigidTransform3D::new(rotation, translation);
        let inverse = rigid.inverse();
        assert!(rigid
            .post_mul(&inverse)
            .to_transform()
            .approx_eq(&TypedTransform3D::identity()));
        assert!(inverse
            .to_transform()
            .approx_eq(&rigid.to_transform().inverse().unwrap()));
    }

    #[test]
    fn test_rigid_multiply() {
        let translation = Vector3D::new(12.1, 17.8, -5.5);
        let rotation = Rotation3D::unit_quaternion(0.5, -7.8, 2.2, 4.3);
        let translation2 = Vector3D::new(9.3, -3.9, 1.1);
        let rotation2 = Rotation3D::unit_quaternion(0.1, 0.2, 0.3, -0.4);
        let rigid = RigidTransform3D::new(rotation, translation);
        let rigid2 = RigidTransform3D::new(rotation2, translation2);

        assert!(rigid
            .post_mul(&rigid2)
            .to_transform()
            .approx_eq(&rigid.to_transform().post_mul(&rigid2.to_transform())));
        assert!(rigid
            .pre_mul(&rigid2)
            .to_transform()
            .approx_eq(&rigid.to_transform().pre_mul(&rigid2.to_transform())));
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use scope::Scope;
use ast::{Expr, EvalResult};
use ast::EvalError::*;

pub struct State<'s> {
    default_ns: String,
    namespaces: HashMap<String, Scope<'s>>,
    parent: Option<&'s State<'s>>,
}

impl<'s> State<'s> {
    pub fn new(default: String) -> State<'s> {
        State {
            default_ns: default,
            namespaces: HashMap::new(),
            parent: None,
        }
    }

    pub fn insert(&mut self, ns: Option<String>, name: String, expr: Expr) -> Option<Expr> {
        self.namespaces
            .get_mut(ns.as_ref().unwrap_or(&self.default_ns))
            .and_then(|scope| scope.insert(name, expr))
    }

    pub fn get(&self, ns: Option<String>, name: &String) -> Option<&Expr> {
        let mut state = self;
        loop {
            let v = state.namespaces
                         .get(ns.as_ref().unwrap_or(&self.default_ns))
                         .and_then(|scope| scope.get(name));
            if v.is_none() && state.parent.is_some() {
                state = state.parent.unwrap();
            } else {
                return v
            }
        }
    }

    pub fn eval(&self, expr: &Expr) -> EvalResult {
        match try!(self.expand(expr)) {
            ref sym_expr @ Expr::Symbol { .. } => {
                self.eval_symbol(sym_expr)
            },
            ref def_expr @ Expr::Def { .. } => {
                self.eval_def(def_expr)
            },
            ref call_expr @ Expr::Call { .. } => {
                self.eval_call(call_expr)
            },
            ref let_expr @ Expr::Let { .. } => {
                self.eval_let(let_expr)
            },
            other_expr => {
                Ok(other_expr)
            },
        }
    }

    fn eval_symbol(&self, expr: &Expr) -> EvalResult {
        if let Expr::Symbol { ref ns, ref name , .. } = *expr {
            let ns_name = ns.as_ref().unwrap_or(&self.default_ns);
            match self.namespaces.get(ns_name) {
                Some(scope) => {
                    scope.get(name)
                         .map_or(Err(ResolveError(name.clone())), |e| Ok(e.clone()))
                },
                None => {
                    Err(ResolveError(ns_name.clone()))
                }
            }
        } else {
            Err(DispatchError(expr.clone()))
        }
    }

    fn eval_def(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn eval_call(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn eval_let(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand(&self, expr: &Expr) -> EvalResult {
        if let Expr::List(ref l) = *expr {
            if l.len() > 0 {
                if let Expr::Symbol { ref name, .. } = l[0] {
                    match &name[..] {
                        "def" => {
                            return self.expand_def(expr)
                        },
                        "fn" => {
                            return self.expand_fn(expr)
                        },
                        "macro" => {
                            return self.expand_macro(expr)
                        },
                        "quote" => {
                            return self.expand_quote(expr)
                        },
                        "unquote" => {
                            return self.expand_unquote(expr)
                        },
                        "unquote-splicing" => {
                            return self.expand_unquote_splicing(expr)
                        },
                        "let" => {
                            return self.expand_let(expr)
                        },
                        _ => {
                            return self.expand_call(expr)
                        }
                    }
                } else {
                    return Err(DispatchError(l[0].clone()))
                }
            }
        }
        Ok(expr.clone())
    }

    fn expand_def(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_fn(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_macro(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_quote(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_unquote(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_unquote_splicing(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_let(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_call(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

}
<commit_msg>Implement new_chained state constructor function<commit_after>use std::collections::HashMap;
use scope::Scope;
use ast::{Expr, EvalResult};
use ast::EvalError::*;

pub struct State<'s> {
    default_ns: String,
    namespaces: HashMap<String, Scope<'s>>,
    parent: Option<&'s State<'s>>,
}

impl<'s> State<'s> {
    pub fn new(default: String) -> State<'s> {
        State {
            default_ns: default,
            namespaces: HashMap::new(),
            parent: None,
        }
    }

    pub fn new_chained(parent: &'s State<'s>) -> State<'s> {
        let mut state = State::new(format!("{}_chained", parent.default_ns));
        state.parent = Some(parent);
        state
    }

    pub fn insert(&mut self, ns: Option<String>, name: String, expr: Expr) -> Option<Expr> {
        self.namespaces
            .get_mut(ns.as_ref().unwrap_or(&self.default_ns))
            .and_then(|scope| scope.insert(name, expr))
    }

    pub fn get(&self, ns: Option<String>, name: &String) -> Option<&Expr> {
        let mut state = self;
        loop {
            let v = state.namespaces
                         .get(ns.as_ref().unwrap_or(&self.default_ns))
                         .and_then(|scope| scope.get(name));
            if v.is_none() && state.parent.is_some() {
                state = state.parent.unwrap();
            } else {
                return v
            }
        }
    }

    pub fn eval(&self, expr: &Expr) -> EvalResult {
        match try!(self.expand(expr)) {
            ref sym_expr @ Expr::Symbol { .. } => {
                self.eval_symbol(sym_expr)
            },
            ref def_expr @ Expr::Def { .. } => {
                self.eval_def(def_expr)
            },
            ref call_expr @ Expr::Call { .. } => {
                self.eval_call(call_expr)
            },
            ref let_expr @ Expr::Let { .. } => {
                self.eval_let(let_expr)
            },
            other_expr => {
                Ok(other_expr)
            },
        }
    }

    fn eval_symbol(&self, expr: &Expr) -> EvalResult {
        if let Expr::Symbol { ref ns, ref name , .. } = *expr {
            let ns_name = ns.as_ref().unwrap_or(&self.default_ns);
            match self.namespaces.get(ns_name) {
                Some(scope) => {
                    scope.get(name)
                         .map_or(Err(ResolveError(name.clone())), |e| Ok(e.clone()))
                },
                None => {
                    Err(ResolveError(ns_name.clone()))
                }
            }
        } else {
            Err(DispatchError(expr.clone()))
        }
    }

    fn eval_def(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn eval_call(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn eval_let(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand(&self, expr: &Expr) -> EvalResult {
        if let Expr::List(ref l) = *expr {
            if l.len() > 0 {
                if let Expr::Symbol { ref name, .. } = l[0] {
                    match &name[..] {
                        "def" => {
                            return self.expand_def(expr)
                        },
                        "fn" => {
                            return self.expand_fn(expr)
                        },
                        "macro" => {
                            return self.expand_macro(expr)
                        },
                        "quote" => {
                            return self.expand_quote(expr)
                        },
                        "unquote" => {
                            return self.expand_unquote(expr)
                        },
                        "unquote-splicing" => {
                            return self.expand_unquote_splicing(expr)
                        },
                        "let" => {
                            return self.expand_let(expr)
                        },
                        _ => {
                            return self.expand_call(expr)
                        }
                    }
                } else {
                    return Err(DispatchError(l[0].clone()))
                }
            }
        }
        Ok(expr.clone())
    }

    fn expand_def(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_fn(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_macro(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_quote(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_unquote(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_unquote_splicing(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_let(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

    fn expand_call(&self, expr: &Expr) -> EvalResult {
        Ok(expr.clone())
    }

}
<|endoftext|>