<commit_before>use audio::{AudioData, Operation as AudioOperation};
use camera::Projection;
use color::{self, Color};
use light::{ShadowMap, ShadowProjection};
use material::Material;
use mesh::DynamicMesh;
use node::{NodeInternal, NodePointer, TransformInternal};
use object::Base;
use render::{BackendResources, GpuData};
use skeleton::{Bone, Skeleton};
use text::{Operation as TextOperation, TextData};

use cgmath::Transform;
use froggy;
use gfx;
use mint;

use std::{mem, ops};
use std::sync::{Arc, Mutex};
use std::sync::mpsc;

#[derive(Clone, Debug)]
pub(crate) enum SubLight {
    Ambient,
    Directional,
    Hemisphere { ground: Color },
    Point,
}

#[derive(Clone, Debug)]
pub(crate) struct LightData {
    pub color: Color,
    pub intensity: f32,
    pub sub_light: SubLight,
    pub shadow: Option<(ShadowMap, ShadowProjection)>,
}

#[derive(Clone, Debug)]
pub(crate) struct SkeletonData {
    pub bones: Vec<Bone>,
    pub gpu_buffer_view: gfx::handle::ShaderResourceView<BackendResources, [f32; 4]>,
    pub gpu_buffer: gfx::handle::Buffer<BackendResources, [f32; 4]>,
}

#[derive(Clone, Debug)]
pub(crate) struct VisualData {
    pub material: Material,
    pub gpu: GpuData,
    pub skeleton: Option<Skeleton>,
}

#[derive(Debug)]
pub(crate) enum SubNode {
    /// Camera for rendering a scene.
    Camera(Projection),
    /// Group can be a parent to other objects.
    Group { first_child: Option<NodePointer> },
    /// Audio data.
    Audio(AudioData),
    /// Renderable text for 2D user interface.
    UiText(TextData),
    /// Renderable 3D content, such as a mesh.
    Visual(Material, GpuData, Option<Skeleton>),
    /// Lighting information for illumination and shadow casting.
    Light(LightData),
    /// A single bone.
    Bone { index: usize, inverse_bind_matrix: mint::ColumnMatrix4<f32> },
    /// Skeleton root.
    Skeleton(SkeletonData),
}

pub(crate) type Message = (froggy::WeakPointer<NodeInternal>, Operation);

#[derive(Debug)]
pub(crate) enum Operation {
    AddChild(NodePointer),
    RemoveChild(NodePointer),
    SetAudio(AudioOperation),
    SetVisible(bool),
    SetText(TextOperation),
    SetTransform(
        Option<mint::Point3<f32>>,
        Option<mint::Quaternion<f32>>,
        Option<f32>,
    ),
    SetMaterial(Material),
    SetSkeleton(Skeleton),
    SetShadow(ShadowMap, ShadowProjection),
    SetTexelRange(mint::Point2<i16>, mint::Vector2<u16>),
    SetWeights(Vec<f32>),
    SetName(String),
}

pub(crate) type HubPtr = Arc<Mutex<Hub>>;

pub(crate) struct Hub {
    pub(crate) nodes: froggy::Storage<NodeInternal>,
    pub(crate) message_tx: mpsc::Sender<Message>,
    message_rx: mpsc::Receiver<Message>,
}

impl<T: AsRef<Base>> ops::Index<T> for Hub {
    type Output = NodeInternal;
    fn index(&self, i: T) -> &Self::Output {
        let base: &Base = i.as_ref();
        &self.nodes[&base.node]
    }
}

impl<T: AsRef<Base>> ops::IndexMut<T> for Hub {
    fn index_mut(&mut self, i: T) -> &mut Self::Output {
        let base: &Base = i.as_ref();
        &mut self.nodes[&base.node]
    }
}

impl Hub {
    pub(crate) fn new() -> HubPtr {
        let (tx, rx) = mpsc::channel();
        let hub = Hub {
            nodes: froggy::Storage::new(),
            message_tx: tx,
            message_rx: rx,
        };
        Arc::new(Mutex::new(hub))
    }

    pub(crate) fn spawn(
        &mut self,
        sub: SubNode,
    ) -> Base {
        Base {
            node: self.nodes.create(sub.into()),
            tx: self.message_tx.clone(),
        }
    }

    pub(crate) fn spawn_visual(
        &mut self,
        mat: Material,
        gpu_data: GpuData,
        skeleton: Option<Skeleton>,
    ) -> Base {
        self.spawn(SubNode::Visual(mat, gpu_data, skeleton))
    }

    pub(crate) fn spawn_light(
        &mut self,
        data: LightData,
    ) -> Base {
        self.spawn(SubNode::Light(data))
    }

    pub(crate) fn spawn_skeleton(
        &mut self,
        data: SkeletonData,
    ) -> Base {
        self.spawn(SubNode::Skeleton(data))
    }

    /// Upgrades a `NodePointer` to a `Base`.
    pub(crate) fn upgrade_ptr(&self, ptr: NodePointer) -> Base {
        Base {
            node: ptr,
            tx: self.message_tx.clone(),
        }
    }

    pub(crate) fn process_messages(&mut self) {
        while let Ok((weak_ptr, operation)) = self.message_rx.try_recv() {
            let ptr = match weak_ptr.upgrade() {
                Ok(ptr) => ptr,
                Err(_) => continue,
            };
            match operation {
                Operation::SetAudio(operation) => {
                    if let SubNode::Audio(ref mut data) = self.nodes[&ptr].sub_node {
                        Hub::process_audio(operation, data);
                    }
                },
                Operation::SetVisible(visible) => {
                    self.nodes[&ptr].visible = visible;
                }
                Operation::SetTransform(pos, rot, scale) => {
                    let transform = &mut self.nodes[&ptr].transform;
                    if let Some(pos) = pos {

                        transform.disp = mint::Vector3::from(pos).into();
                    }
                    if let Some(rot) = rot {
                        transform.rot = rot.into();
                    }
                    if let Some(scale) = scale {
                        transform.scale = scale;
                    }
                }
                Operation::AddChild(child_ptr) => {
                    let sibling = match self.nodes[&ptr].sub_node {
                        SubNode::Group { ref mut first_child } =>
                            mem::replace(first_child, Some(child_ptr.clone())),
                        _ => unreachable!(),
                    };
                    let child = &mut self.nodes[&child_ptr];
                    if child.next_sibling.is_some() {
                        error!("Element {:?} is added to a group while still having old parent - {}",
                            child.sub_node, "discarding siblings");
                    }
                    child.next_sibling = sibling;
                }
                Operation::RemoveChild(child_ptr) => {
                    let next_sibling = self.nodes[&child_ptr].next_sibling.clone();
                    let target_maybe = Some(child_ptr);
                    let mut cur_ptr = match self.nodes[&ptr].sub_node {
                        SubNode::Group { ref mut first_child } => {
                            if *first_child == target_maybe {
                                *first_child = next_sibling;
                                continue;
                            }
                            first_child.clone()
                        }
                        _ => unreachable!()
                    };

                    //TODO: consolidate the code with `Scene::remove()`
                    loop {
                        let node = match cur_ptr.take() {
                            Some(next_ptr) => &mut self.nodes[&next_ptr],
                            None => {
                                error!("Unable to find child for removal");
                                break;
                            }
                        };
                        if node.next_sibling == target_maybe {
                            node.next_sibling = next_sibling;
                            break;
                        }
                        cur_ptr = node.next_sibling.clone(); //TODO: avoid clone
                    }
                }
                Operation::SetText(operation) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::UiText(ref mut data) => {
                            Hub::process_text(operation, data);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetMaterial(material) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(ref mut mat, _, _) => {
                            *mat = material;
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetSkeleton(sleketon) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(_, _, ref mut skel) => {
                            *skel = Some(sleketon);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetShadow(map, proj) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Light(ref mut data) => {
                            data.shadow = Some((map, proj));
                        },
                    _ => unreachable!()
                    }
                }
                Operation::SetTexelRange(base, size) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(Material::Sprite(ref mut params), _, _) => {
                            params.map.set_texel_range(base, size);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetWeights(weights) => {
                    fn set_weights(
                        gpu_data: &mut GpuData,
                        weights: &[f32],
                    ) {
                        use std::iter::repeat;
                        for (out, input) in gpu_data.displacement_contributions
                            .iter_mut()
                            .zip(weights.iter().chain(repeat(&0.0)))
                        {
                            out.weight = *input;
                        }
                    }

                    let mut x = match self.nodes[&ptr].sub_node {
                        SubNode::Visual(_, ref mut gpu_data, _) => {
                            set_weights(gpu_data, &weights);
                            continue;
                        }
                        SubNode::Group { ref first_child } => first_child.clone(),
                        _ => continue,
                    };

                    while let Some(ptr) = x {
                        if let SubNode::Visual(_, ref mut gpu_data, _) = self.nodes[&ptr].sub_node {
                            set_weights(gpu_data, &weights);
                        }
                        x = self.nodes[&ptr].next_sibling.clone();
                    }
                }
                Operation::SetName(name) => {
                    self.nodes[&ptr].name = Some(name);
                }
            }
        }

        self.nodes.sync_pending();
    }

    fn process_audio(
        operation: AudioOperation,
        data: &mut AudioData,
    ) {
        match operation {
            AudioOperation::Append(clip) => data.source.append(clip),
            AudioOperation::Pause => data.source.pause(),
            AudioOperation::Resume => data.source.resume(),
            AudioOperation::Stop => data.source.stop(),
            AudioOperation::SetVolume(volume) => data.source.set_volume(volume),
        }
    }

    fn process_text(
        operation: TextOperation,
        data: &mut TextData,
    ) {
        use gfx_glyph::Scale;
        match operation {
            TextOperation::Color(color) => {
                let rgb = color::to_linear_rgb(color);
                data.section.text[0].color = [rgb[0], rgb[1], rgb[2], 1.0];
            }
            TextOperation::Font(font) => data.font = font,
            TextOperation::Layout(layout) => data.layout = layout,
            TextOperation::Opacity(opacity) => data.section.text[0].color[3] = opacity,
            TextOperation::Pos(point) => data.section.screen_position = (point.x, point.y),
            // TODO: somehow grab window::hdpi_factor and multiply size
            TextOperation::Scale(scale) => data.section.text[0].scale = Scale::uniform(scale),
            TextOperation::Size(size) => data.section.bounds = (size.x, size.y),
            TextOperation::Text(text) => data.section.text[0].text = text,
        }
    }

    pub(crate) fn update_mesh(
        &mut self,
        mesh: &DynamicMesh,
    ) {
        match self[mesh].sub_node {
            SubNode::Visual(_, ref mut gpu_data, _) => gpu_data.pending = Some(mesh.dynamic.clone()),
            _ => unreachable!(),
        }
    }

    fn walk_impl(
        &self, base: &Option<NodePointer>, only_visible: bool
    ) -> TreeWalker {
        let default_stack_size = 10;
        let mut walker = TreeWalker {
            hub: self,
            only_visible,
            stack: Vec::with_capacity(default_stack_size),
        };
        walker.descend(base);
        walker
    }

    pub(crate) fn walk(&self, base: &Option<NodePointer>) -> TreeWalker {
        self.walk_impl(base, true)
    }

    pub(crate) fn walk_all(&self, base: &Option<NodePointer>) -> TreeWalker {
        self.walk_impl(base, false)
    }
}

#[derive(Debug)]
pub(crate) struct WalkedNode<'a> {
    pub(crate) node_ptr: NodePointer,
    pub(crate) node: &'a NodeInternal,
    pub(crate) world_visible: bool,
    pub(crate) world_transform: TransformInternal,
}

pub(crate) struct TreeWalker<'a> {
    hub: &'a Hub,
    only_visible: bool,
    stack: Vec<WalkedNode<'a>>,
}

impl<'a> TreeWalker<'a> {
    fn descend(&mut self, base: &Option<NodePointer>) -> Option<&NodeInternal> {
        let base = base.as_ref()?;
        // Note: this is a CPU hotspot, presumably for copying stuff around
        // TODO: profile carefully and optimize
        let mut node = &self.hub.nodes[base];

        loop {
            let wn = match self.stack.last() {
                Some(parent) => WalkedNode {
                    node_ptr: base.clone(),
                    node,
                    world_visible: parent.world_visible && node.visible,
                    world_transform: parent.world_transform.concat(&node.transform),
                },
                None => WalkedNode {
                    node_ptr: base.clone(),
                    node,
                    world_visible: node.visible,
                    world_transform: node.transform,
                },
            };
            self.stack.push(wn);

            if self.only_visible && !node.visible {
                break;
            }

            node = match node.sub_node {
                SubNode::Group { first_child: Some(ref ptr) } => &self.hub.nodes[ptr],
                _ => break,
            };
        }

        Some(node)
    }
}

impl<'a> Iterator for TreeWalker<'a> {
    type Item = WalkedNode<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(top) = self.stack.pop() {
            self.descend(&top.node.next_sibling);
            if !self.only_visible || top.world_visible {
                return Some(top)
            }
        }
        None
    }
}
<commit_msg>Fix node pointer tracking in WalkedNode<commit_after>use audio::{AudioData, Operation as AudioOperation};
use camera::Projection;
use color::{self, Color};
use light::{ShadowMap, ShadowProjection};
use material::Material;
use mesh::DynamicMesh;
use node::{NodeInternal, NodePointer, TransformInternal};
use object::Base;
use render::{BackendResources, GpuData};
use skeleton::{Bone, Skeleton};
use text::{Operation as TextOperation, TextData};

use cgmath::Transform;
use froggy;
use gfx;
use mint;

use std::{mem, ops};
use std::sync::{Arc, Mutex};
use std::sync::mpsc;

#[derive(Clone, Debug)]
pub(crate) enum SubLight {
    Ambient,
    Directional,
    Hemisphere { ground: Color },
    Point,
}

#[derive(Clone, Debug)]
pub(crate) struct LightData {
    pub color: Color,
    pub intensity: f32,
    pub sub_light: SubLight,
    pub shadow: Option<(ShadowMap, ShadowProjection)>,
}

#[derive(Clone, Debug)]
pub(crate) struct SkeletonData {
    pub bones: Vec<Bone>,
    pub gpu_buffer_view: gfx::handle::ShaderResourceView<BackendResources, [f32; 4]>,
    pub gpu_buffer: gfx::handle::Buffer<BackendResources, [f32; 4]>,
}

#[derive(Clone, Debug)]
pub(crate) struct VisualData {
    pub material: Material,
    pub gpu: GpuData,
    pub skeleton: Option<Skeleton>,
}

#[derive(Debug)]
pub(crate) enum SubNode {
    /// Camera for rendering a scene.
    Camera(Projection),
    /// Group can be a parent to other objects.
    Group { first_child: Option<NodePointer> },
    /// Audio data.
    Audio(AudioData),
    /// Renderable text for 2D user interface.
    UiText(TextData),
    /// Renderable 3D content, such as a mesh.
    Visual(Material, GpuData, Option<Skeleton>),
    /// Lighting information for illumination and shadow casting.
    Light(LightData),
    /// A single bone.
    Bone { index: usize, inverse_bind_matrix: mint::ColumnMatrix4<f32> },
    /// Skeleton root.
    Skeleton(SkeletonData),
}

pub(crate) type Message = (froggy::WeakPointer<NodeInternal>, Operation);

#[derive(Debug)]
pub(crate) enum Operation {
    AddChild(NodePointer),
    RemoveChild(NodePointer),
    SetAudio(AudioOperation),
    SetVisible(bool),
    SetText(TextOperation),
    SetTransform(
        Option<mint::Point3<f32>>,
        Option<mint::Quaternion<f32>>,
        Option<f32>,
    ),
    SetMaterial(Material),
    SetSkeleton(Skeleton),
    SetShadow(ShadowMap, ShadowProjection),
    SetTexelRange(mint::Point2<i16>, mint::Vector2<u16>),
    SetWeights(Vec<f32>),
    SetName(String),
}

pub(crate) type HubPtr = Arc<Mutex<Hub>>;

pub(crate) struct Hub {
    pub(crate) nodes: froggy::Storage<NodeInternal>,
    pub(crate) message_tx: mpsc::Sender<Message>,
    message_rx: mpsc::Receiver<Message>,
}

impl<T: AsRef<Base>> ops::Index<T> for Hub {
    type Output = NodeInternal;
    fn index(&self, i: T) -> &Self::Output {
        let base: &Base = i.as_ref();
        &self.nodes[&base.node]
    }
}

impl<T: AsRef<Base>> ops::IndexMut<T> for Hub {
    fn index_mut(&mut self, i: T) -> &mut Self::Output {
        let base: &Base = i.as_ref();
        &mut self.nodes[&base.node]
    }
}

impl Hub {
    pub(crate) fn new() -> HubPtr {
        let (tx, rx) = mpsc::channel();
        let hub = Hub {
            nodes: froggy::Storage::new(),
            message_tx: tx,
            message_rx: rx,
        };
        Arc::new(Mutex::new(hub))
    }

    pub(crate) fn spawn(
        &mut self,
        sub: SubNode,
    ) -> Base {
        Base {
            node: self.nodes.create(sub.into()),
            tx: self.message_tx.clone(),
        }
    }

    pub(crate) fn spawn_visual(
        &mut self,
        mat: Material,
        gpu_data: GpuData,
        skeleton: Option<Skeleton>,
    ) -> Base {
        self.spawn(SubNode::Visual(mat, gpu_data, skeleton))
    }

    pub(crate) fn spawn_light(
        &mut self,
        data: LightData,
    ) -> Base {
        self.spawn(SubNode::Light(data))
    }

    pub(crate) fn spawn_skeleton(
        &mut self,
        data: SkeletonData,
    ) -> Base {
        self.spawn(SubNode::Skeleton(data))
    }

    /// Upgrades a `NodePointer` to a `Base`.
    pub(crate) fn upgrade_ptr(&self, ptr: NodePointer) -> Base {
        Base {
            node: ptr,
            tx: self.message_tx.clone(),
        }
    }

    pub(crate) fn process_messages(&mut self) {
        while let Ok((weak_ptr, operation)) = self.message_rx.try_recv() {
            let ptr = match weak_ptr.upgrade() {
                Ok(ptr) => ptr,
                Err(_) => continue,
            };
            match operation {
                Operation::SetAudio(operation) => {
                    if let SubNode::Audio(ref mut data) = self.nodes[&ptr].sub_node {
                        Hub::process_audio(operation, data);
                    }
                },
                Operation::SetVisible(visible) => {
                    self.nodes[&ptr].visible = visible;
                }
                Operation::SetTransform(pos, rot, scale) => {
                    let transform = &mut self.nodes[&ptr].transform;
                    if let Some(pos) = pos {

                        transform.disp = mint::Vector3::from(pos).into();
                    }
                    if let Some(rot) = rot {
                        transform.rot = rot.into();
                    }
                    if let Some(scale) = scale {
                        transform.scale = scale;
                    }
                }
                Operation::AddChild(child_ptr) => {
                    let sibling = match self.nodes[&ptr].sub_node {
                        SubNode::Group { ref mut first_child } =>
                            mem::replace(first_child, Some(child_ptr.clone())),
                        _ => unreachable!(),
                    };
                    let child = &mut self.nodes[&child_ptr];
                    if child.next_sibling.is_some() {
                        error!("Element {:?} is added to a group while still having old parent - {}",
                            child.sub_node, "discarding siblings");
                    }
                    child.next_sibling = sibling;
                }
                Operation::RemoveChild(child_ptr) => {
                    let next_sibling = self.nodes[&child_ptr].next_sibling.clone();
                    let target_maybe = Some(child_ptr);
                    let mut cur_ptr = match self.nodes[&ptr].sub_node {
                        SubNode::Group { ref mut first_child } => {
                            if *first_child == target_maybe {
                                *first_child = next_sibling;
                                continue;
                            }
                            first_child.clone()
                        }
                        _ => unreachable!()
                    };

                    //TODO: consolidate the code with `Scene::remove()`
                    loop {
                        let node = match cur_ptr.take() {
                            Some(next_ptr) => &mut self.nodes[&next_ptr],
                            None => {
                                error!("Unable to find child for removal");
                                break;
                            }
                        };
                        if node.next_sibling == target_maybe {
                            node.next_sibling = next_sibling;
                            break;
                        }
                        cur_ptr = node.next_sibling.clone(); //TODO: avoid clone
                    }
                }
                Operation::SetText(operation) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::UiText(ref mut data) => {
                            Hub::process_text(operation, data);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetMaterial(material) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(ref mut mat, _, _) => {
                            *mat = material;
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetSkeleton(sleketon) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(_, _, ref mut skel) => {
                            *skel = Some(sleketon);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetShadow(map, proj) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Light(ref mut data) => {
                            data.shadow = Some((map, proj));
                        },
                    _ => unreachable!()
                    }
                }
                Operation::SetTexelRange(base, size) => {
                    match self.nodes[&ptr].sub_node {
                        SubNode::Visual(Material::Sprite(ref mut params), _, _) => {
                            params.map.set_texel_range(base, size);
                        }
                        _ => unreachable!()
                    }
                }
                Operation::SetWeights(weights) => {
                    fn set_weights(
                        gpu_data: &mut GpuData,
                        weights: &[f32],
                    ) {
                        use std::iter::repeat;
                        for (out, input) in gpu_data.displacement_contributions
                            .iter_mut()
                            .zip(weights.iter().chain(repeat(&0.0)))
                        {
                            out.weight = *input;
                        }
                    }

                    let mut x = match self.nodes[&ptr].sub_node {
                        SubNode::Visual(_, ref mut gpu_data, _) => {
                            set_weights(gpu_data, &weights);
                            continue;
                        }
                        SubNode::Group { ref first_child } => first_child.clone(),
                        _ => continue,
                    };

                    while let Some(ptr) = x {
                        if let SubNode::Visual(_, ref mut gpu_data, _) = self.nodes[&ptr].sub_node {
                            set_weights(gpu_data, &weights);
                        }
                        x = self.nodes[&ptr].next_sibling.clone();
                    }
                }
                Operation::SetName(name) => {
                    self.nodes[&ptr].name = Some(name);
                }
            }
        }

        self.nodes.sync_pending();
    }

    fn process_audio(
        operation: AudioOperation,
        data: &mut AudioData,
    ) {
        match operation {
            AudioOperation::Append(clip) => data.source.append(clip),
            AudioOperation::Pause => data.source.pause(),
            AudioOperation::Resume => data.source.resume(),
            AudioOperation::Stop => data.source.stop(),
            AudioOperation::SetVolume(volume) => data.source.set_volume(volume),
        }
    }

    fn process_text(
        operation: TextOperation,
        data: &mut TextData,
    ) {
        use gfx_glyph::Scale;
        match operation {
            TextOperation::Color(color) => {
                let rgb = color::to_linear_rgb(color);
                data.section.text[0].color = [rgb[0], rgb[1], rgb[2], 1.0];
            }
            TextOperation::Font(font) => data.font = font,
            TextOperation::Layout(layout) => data.layout = layout,
            TextOperation::Opacity(opacity) => data.section.text[0].color[3] = opacity,
            TextOperation::Pos(point) => data.section.screen_position = (point.x, point.y),
            // TODO: somehow grab window::hdpi_factor and multiply size
            TextOperation::Scale(scale) => data.section.text[0].scale = Scale::uniform(scale),
            TextOperation::Size(size) => data.section.bounds = (size.x, size.y),
            TextOperation::Text(text) => data.section.text[0].text = text,
        }
    }

    pub(crate) fn update_mesh(
        &mut self,
        mesh: &DynamicMesh,
    ) {
        match self[mesh].sub_node {
            SubNode::Visual(_, ref mut gpu_data, _) => gpu_data.pending = Some(mesh.dynamic.clone()),
            _ => unreachable!(),
        }
    }

    fn walk_impl(
        &self, base: &Option<NodePointer>, only_visible: bool
    ) -> TreeWalker {
        let default_stack_size = 10;
        let mut walker = TreeWalker {
            hub: self,
            only_visible,
            stack: Vec::with_capacity(default_stack_size),
        };
        walker.descend(base);
        walker
    }

    pub(crate) fn walk(&self, base: &Option<NodePointer>) -> TreeWalker {
        self.walk_impl(base, true)
    }

    pub(crate) fn walk_all(&self, base: &Option<NodePointer>) -> TreeWalker {
        self.walk_impl(base, false)
    }
}

#[derive(Debug)]
pub(crate) struct WalkedNode<'a> {
    pub(crate) node_ptr: NodePointer,
    pub(crate) node: &'a NodeInternal,
    pub(crate) world_visible: bool,
    pub(crate) world_transform: TransformInternal,
}

pub(crate) struct TreeWalker<'a> {
    hub: &'a Hub,
    only_visible: bool,
    stack: Vec<WalkedNode<'a>>,
}

impl<'a> TreeWalker<'a> {
    fn descend(&mut self, base: &Option<NodePointer>) -> Option<&NodeInternal> {
        // Unwrap the base pointer, returning `None` if `base` is `None`.
        let mut ptr = base.as_ref()?;

        // Note: this is a CPU hotspot, presumably for copying stuff around
        // TODO: profile carefully and optimize
        let mut node = &self.hub.nodes[ptr];

        loop {
            let wn = match self.stack.last() {
                Some(parent) => WalkedNode {
                    node_ptr: ptr.clone(),
                    node,
                    world_visible: parent.world_visible && node.visible,
                    world_transform: parent.world_transform.concat(&node.transform),
                },
                None => WalkedNode {
                    node_ptr: ptr.clone(),
                    node,
                    world_visible: node.visible,
                    world_transform: node.transform,
                },
            };
            self.stack.push(wn);

            if self.only_visible && !node.visible {
                break;
            }

            match node.sub_node {
                SubNode::Group { first_child: Some(ref child_ptr) } => {
                    ptr = child_ptr;
                    node = &self.hub.nodes[&ptr];
                },
                _ => break,
            }
        }

        Some(node)
    }
}

impl<'a> Iterator for TreeWalker<'a> {
    type Item = WalkedNode<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        while let Some(top) = self.stack.pop() {
            self.descend(&top.node.next_sibling);
            if !self.only_visible || top.world_visible {
                return Some(top)
            }
        }
        None
    }
}
<|endoftext|>


<commit_before>// Conversion between machine integers.

cfg_if! (
    if #[cfg(feature="no_std")] {
        use core::{u8, u16, u32, u64, usize, i8, i16, i32, i64, isize};
        use core::fmt::{self, Display, Formatter};
        use core::mem;
    } else {
        use std::{u8, u16, u32, u64, usize, i8, i16, i32, i64, isize};
        use std::error::Error;
        use std::fmt::{self, Display, Formatter};
        use std::mem;
    }
);

use {TryFrom, Void};

/// Error which occurs when conversion from one integer type to another fails.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TryFromIntError {
    Overflow,
    Underflow,
}

impl TryFromIntError {
    fn as_str(self) -> &'static str {
        match self {
            TryFromIntError::Overflow => "integer overflow",
            TryFromIntError::Underflow => "integer underflow",
        }
    }
}

impl Display for TryFromIntError {
    fn fmt(&self, n: &mut Formatter) -> fmt::Result {
        n.write_str(self.as_str())
    }
}

cfg_if! (
    if #[cfg(not(feature="no_std"))] {
        impl Error for TryFromIntError {
            fn description(&self) -> &str {
                self.as_str()
            }
        }
    }
);

macro_rules! impl_infallible {
    { $($t:ident from $($f:ident),*;)* } => { $($(
        impl TryFrom<$f> for $t {
            type Err = Void;
            fn try_from (n: $f) -> Result<$t, Void> { Ok(n as $t) }
        }
    )*)* };
}

impl_infallible! {
    u8 from u8;
    u16 from u8, u16;
    u32 from u8, u16, u32;
    u64 from u8, u16, u32, u64, usize;
    usize from u8, u16, u32, usize;
    i8 from i8;
    i16 from u8, i8, i16;
    i32 from u8, u16, i8, i16, i32;
    i64 from u8, u16, u32, i8, i16, i32, i64, isize;
    isize from u8, u16, i8, i16, i32, isize;
}

#[test]
fn test_infallible() {
    assert_eq!(u64::try_from(usize::MAX), Ok(usize::MAX as u64));
}

macro_rules! impl_unsigned_from_unsigned {
    { $($t:ident from $($f:ident),*;)* } => { $($(
        impl TryFrom<$f> for $t {
            type Err = TryFromIntError;

            fn try_from (n: $f) -> Result<$t, TryFromIntError> {
                if mem::size_of::<$f>() > mem::size_of::<$t>() && n > $t::MAX as $f {
                    Err(TryFromIntError::Overflow)
                } else {
                    Ok(n as $t)
                }
            }
        }
    )*)* };
}

impl_unsigned_from_unsigned! {
    u8 from u16, u32, u64, usize;
    u16 from u32, u64, usize;
    u32 from u64, usize;
    usize from u64;
}

#[test]
fn test_unsigned_from_unsigned() {
    assert_eq!(u8::try_from(0xffu16), Ok(0xffu8));
    assert_eq!(u8::try_from(0x100u16), Err(TryFromIntError::Overflow));

    if cfg!(target_pointer_width = "32") {
        assert_eq!(u32::try_from(usize::MAX), Ok(u32::MAX));
        assert_eq!(usize::try_from(u64::MAX), Err(TryFromIntError::Overflow));
    } else if cfg!(target_pointer_width = "64") {
        assert_eq!(u32::try_from(usize::MAX), Err(TryFromIntError::Overflow));
        assert_eq!(usize::try_from(u64::MAX), Ok(usize::MAX));
    }
}

macro_rules! impl_unsigned_from_signed {
    { $($t:ident from $($f:ident),*;)* } => { $($(
        impl TryFrom<$f> for $t {
            type Err = TryFromIntError;

            fn try_from (n: $f) -> Result<$t, TryFromIntError> {
                if n < 0 {
                    Err(TryFromIntError::Underflow)
                } else if mem::size_of::<$f>() > mem::size_of::<$t>() && n > $t::MAX as $f {
                    Err(TryFromIntError::Overflow)
                } else {
                    Ok(n as $t)
                }
            }
        }
    )*)* };
}

impl_unsigned_from_signed! {
    u8 from i8, i16, i32, i64, isize;
    u16 from i8, i16, i32, i64, isize;
    u32 from i8, i16, i32, i64, isize;
    u64 from i8, i16, i32, i64, isize;
    usize from i8, i16, i32, i64, isize;
}

#[test]
fn test_unsigned_from_signed() {
    assert_eq!(u8::try_from(0i16), Ok(0u8));
    assert_eq!(u8::try_from(-1i16), Err(TryFromIntError::Underflow));
    assert_eq!(u8::try_from(256i16), Err(TryFromIntError::Overflow));

    if cfg!(target_pointer_width = "32") {
        assert_eq!(u32::try_from(isize::MAX), Ok(0x7fff_ffffu32));
        assert_eq!(usize::try_from(i64::MAX), Err(TryFromIntError::Overflow));
    } else if cfg!(target_pointer_width = "64") {
        assert_eq!(u32::try_from(isize::MAX), Err(TryFromIntError::Overflow));
        assert!(usize::try_from(i64::MAX).unwrap() > 0xffff_ffffusize);
    }
}

macro_rules! impl_signed_from_unsigned {
    { $($t:ident from $($f:ident),*;)* } => { $($(
        impl TryFrom<$f> for $t {
            type Err = TryFromIntError;

            fn try_from (n: $f) -> Result<$t, TryFromIntError> {
                if mem::size_of::<$f>() >= mem::size_of::<$t>() && n > $t::MAX as $f {
                    Err(TryFromIntError::Overflow)
                } else {
                    Ok(n as $t)
                }
            }
        }
    )*)* };
}

impl_signed_from_unsigned! {
    i8 from u8, u16, u32, u64, usize;
    i16 from u16, u32, u64, usize;
    i32 from u32, u64, usize;
    i64 from u64, usize;
    isize from u32, u64, usize;
}

#[test]
fn test_signed_from_unsigned() {
    assert_eq!(i8::try_from(0x7fu8), Ok(0x7fi8));
    assert_eq!(i8::try_from(0x80u8), Err(TryFromIntError::Overflow));

    if cfg!(target_pointer_width = "32") {
        assert_eq!(i64::try_from(usize::MAX), Ok(0xffff_ffffi64));
        assert_eq!(
            isize::try_from(0x8000_0000u64),
            Err(TryFromIntError::Overflow)
        );
    } else if cfg!(target_pointer_width = "64") {
        assert_eq!(i64::try_from(usize::MAX), Err(TryFromIntError::Overflow));
        assert!(isize::try_from(0x8000_0000u64).unwrap() > 0x7fff_ffff);
    }
}

macro_rules! impl_signed_from_signed {
    { $($t:ident from $($f:ident),*;)* } => { $($(
        impl TryFrom<$f> for $t {
            type Err = TryFromIntError;

            fn try_from (n: $f) -> Result<$t, TryFromIntError> {
                if mem::size_of::<$f>() > mem::size_of::<$t>() {
                    if n > $t::MAX as $f {
                        return Err(TryFromIntError::Overflow);
                    } else if n < $t::MIN as $f {
                        return Err(TryFromIntError::Underflow);
                    }
                }
                Ok(n as $t)
            }
        }
    )*)* };
}

impl_signed_from_signed! {
    i8 from i16, i32, i64, isize;
    i16 from i32, i64, isize;
    i32 from i64, isize;
    isize from i64;
}

#[test]
fn test_signed_from_signed() {
    assert_eq!(i8::try_from(127i16), Ok(127i8));
    assert_eq!(i8::try_from(128i16), Err(TryFromIntError::Overflow));
    assert_eq!(i8::try_from(-128i16), Ok(-128i8));
    assert_eq!(i8::try_from(-129i16), Err(TryFromIntError::Underflow));

    if cfg!(target_pointer_width = "32") {
        assert_eq!(i32::try_from(isize::MAX), Ok(i32::MAX));
        assert_eq!(isize::try_from(i64::MAX), Err(TryFromIntError::Overflow));
    } else if cfg!(target_pointer_width = "64") {
        assert_eq!(i32::try_from(isize::MAX), Err(TryFromIntError::Overflow));
        assert!(isize::try_from(i64::MAX).unwrap() > 0x7fff_ffffisize);
    }
}
<commit_msg>Add support for {i,u}128<commit_after>// Conversion between machine integers.

cfg_if! (
    if #[cfg(feature="no_std")] {
        use core::{u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize};
        use core::fmt::{self, Display, Formatter};
        use core::mem;
    } else {
        use std::{u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize};
        use std::error::Error;
        use std::fmt::{self, Display, Formatter};
        use std::mem;
    }
);

use {TryFrom, Void};

/// Error which occurs when conversion from one integer type to another fails.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TryFromIntError {
    Overflow,
    Underflow,
}

impl TryFromIntError {
    fn as_str(self) -> &'static str {
        match self {
            TryFromIntError::Overflow => "integer overflow",
            TryFromIntError::Underflow => "integer underflow",
        }
    }
}

impl Display for TryFromIntError {
    fn fmt(&self, n: &mut Formatter) -> fmt::Result {
        n.write_str(self.as_str())
    }
}

cfg_if! (
    if #[cfg(not(feature="no_std"))] {
        impl Error for TryFromIntError {
            fn description(&self) -> &str {
                self.as_str()
            }
        }
    }
);

macro_rules! impl_infallible {
    { $($t:ident from $($f:ident),*;)* } => { $($(
        impl TryFrom<$f> for $t {
            type Err = Void;
            fn try_from (n: $f) -> Result<$t, Void> { Ok(n as $t) }
        }
    )*)* };
}

impl_infallible! {
    u8 from u8;
    u16 from u8, u16;
    u32 from u8, u16, u32;
    u64 from u8, u16, u32, u64, usize;
    u128 from u8, u16, u32, u64, u128;
    usize from u8, u16, u32, usize;
    i8 from i8;
    i16 from u8, i8, i16;
    i32 from u8, u16, i8, i16, i32;
    i64 from u8, u16, u32, i8, i16, i32, i64, isize;
    i128 from i8, i16, i32, i64, i128;
    isize from u8, u16, i8, i16, i32, isize;
}

#[test]
fn test_infallible() {
    assert_eq!(u64::try_from(usize::MAX), Ok(usize::MAX as u64));
}

macro_rules! impl_unsigned_from_unsigned {
    { $($t:ident from $($f:ident),*;)* } => { $($(
        impl TryFrom<$f> for $t {
            type Err = TryFromIntError;

            fn try_from (n: $f) -> Result<$t, TryFromIntError> {
                if mem::size_of::<$f>() > mem::size_of::<$t>() && n > $t::MAX as $f {
                    Err(TryFromIntError::Overflow)
                } else {
                    Ok(n as $t)
                }
            }
        }
    )*)* };
}

impl_unsigned_from_unsigned! {
    u8 from u16, u32, u64, u128, usize;
    u16 from u32, u64, u128, usize;
    u32 from u64, u128, usize;
    u64 from u128;
    usize from u64, u128;
}

#[test]
fn test_unsigned_from_unsigned() {
    assert_eq!(u8::try_from(0xffu16), Ok(0xffu8));
    assert_eq!(u8::try_from(0x100u16), Err(TryFromIntError::Overflow));

    if cfg!(target_pointer_width = "32") {
        assert_eq!(u32::try_from(usize::MAX), Ok(u32::MAX));
        assert_eq!(usize::try_from(u64::MAX), Err(TryFromIntError::Overflow));
    } else if cfg!(target_pointer_width = "64") {
        assert_eq!(u32::try_from(usize::MAX), Err(TryFromIntError::Overflow));
        assert_eq!(usize::try_from(u64::MAX), Ok(usize::MAX));
    }
}

macro_rules! impl_unsigned_from_signed {
    { $($t:ident from $($f:ident),*;)* } => { $($(
        impl TryFrom<$f> for $t {
            type Err = TryFromIntError;

            fn try_from (n: $f) -> Result<$t, TryFromIntError> {
                if n < 0 {
                    Err(TryFromIntError::Underflow)
                } else if mem::size_of::<$f>() > mem::size_of::<$t>() && n > $t::MAX as $f {
                    Err(TryFromIntError::Overflow)
                } else {
                    Ok(n as $t)
                }
            }
        }
    )*)* };
}

impl_unsigned_from_signed! {
    u8 from i8, i16, i32, i64, i128, isize;
    u16 from i8, i16, i32, i64, i128, isize;
    u32 from i8, i16, i32, i64, i128, isize;
    u64 from i8, i16, i32, i64, i128, isize;
    u128 from i8, i16, i32, i64, i128, isize;
    usize from i8, i16, i32, i64, i128, isize;
}

#[test]
fn test_unsigned_from_signed() {
    assert_eq!(u8::try_from(0i16), Ok(0u8));
    assert_eq!(u8::try_from(-1i16), Err(TryFromIntError::Underflow));
    assert_eq!(u8::try_from(256i16), Err(TryFromIntError::Overflow));

    assert_eq!(u128::try_from(i32::MAX), Ok(i32::MAX as u128));
    assert_eq!(u128::try_from(-1i32), Err(TryFromIntError::Underflow));
    if cfg!(target_pointer_width = "32") {
        assert_eq!(u32::try_from(isize::MAX), Ok(0x7fff_ffffu32));
        assert_eq!(usize::try_from(i64::MAX), Err(TryFromIntError::Overflow));
    } else if cfg!(target_pointer_width = "64") {
        assert_eq!(u32::try_from(isize::MAX), Err(TryFromIntError::Overflow));
        assert!(usize::try_from(i64::MAX).unwrap() > 0xffff_ffffusize);
    }
}

macro_rules! impl_signed_from_unsigned {
    { $($t:ident from $($f:ident),*;)* } => { $($(
        impl TryFrom<$f> for $t {
            type Err = TryFromIntError;

            fn try_from (n: $f) -> Result<$t, TryFromIntError> {
                if mem::size_of::<$f>() >= mem::size_of::<$t>() && n > $t::MAX as $f {
                    Err(TryFromIntError::Overflow)
                } else {
                    Ok(n as $t)
                }
            }
        }
    )*)* };
}

impl_signed_from_unsigned! {
    i8 from u8, u16, u32, u64, u128, usize;
    i16 from u16, u32, u64, u128, usize;
    i32 from u32, u64, u128, usize;
    i64 from u64, u128, usize;
    isize from u32, u64, u128, usize;
}

#[test]
fn test_signed_from_unsigned() {
    assert_eq!(i8::try_from(0x7fu8), Ok(0x7fi8));
    assert_eq!(i8::try_from(0x80u8), Err(TryFromIntError::Overflow));

    assert_eq!(i64::try_from(i64::MAX as u128), Ok(i64::MAX));
    assert_eq!(i64::try_from(u128::MAX), Err(TryFromIntError::Overflow));
    if cfg!(target_pointer_width = "32") {
        assert_eq!(i64::try_from(usize::MAX), Ok(0xffff_ffffi64));
        assert_eq!(
            isize::try_from(0x8000_0000u64),
            Err(TryFromIntError::Overflow)
        );
    } else if cfg!(target_pointer_width = "64") {
        assert_eq!(i64::try_from(usize::MAX), Err(TryFromIntError::Overflow));
        assert!(isize::try_from(0x8000_0000u64).unwrap() > 0x7fff_ffff);
    }
}

macro_rules! impl_signed_from_signed {
    { $($t:ident from $($f:ident),*;)* } => { $($(
        impl TryFrom<$f> for $t {
            type Err = TryFromIntError;

            fn try_from (n: $f) -> Result<$t, TryFromIntError> {
                if mem::size_of::<$f>() > mem::size_of::<$t>() {
                    if n > $t::MAX as $f {
                        return Err(TryFromIntError::Overflow);
                    } else if n < $t::MIN as $f {
                        return Err(TryFromIntError::Underflow);
                    }
                }
                Ok(n as $t)
            }
        }
    )*)* };
}

impl_signed_from_signed! {
    i8 from i16, i32, i64, i128, isize;
    i16 from i32, i64, i128, isize;
    i32 from i64, i128, isize;
    i64 from i128;
    isize from i64, i128;
}

#[test]
fn test_signed_from_signed() {
    assert_eq!(i8::try_from(127i16), Ok(127i8));
    assert_eq!(i8::try_from(128i16), Err(TryFromIntError::Overflow));
    assert_eq!(i8::try_from(-128i16), Ok(-128i8));
    assert_eq!(i8::try_from(-129i16), Err(TryFromIntError::Underflow));

    assert_eq!(i64::try_from(i64::MAX as i128), Ok(i64::MAX));
    assert_eq!(i64::try_from(i128::MAX), Err(TryFromIntError::Overflow));

    if cfg!(target_pointer_width = "32") {
        assert_eq!(i32::try_from(isize::MAX), Ok(i32::MAX));
        assert_eq!(isize::try_from(i64::MAX), Err(TryFromIntError::Overflow));
    } else if cfg!(target_pointer_width = "64") {
        assert_eq!(i32::try_from(isize::MAX), Err(TryFromIntError::Overflow));
        assert!(isize::try_from(i64::MAX).unwrap() > 0x7fff_ffffisize);
    }
}
<|endoftext|>


<commit_before>use atom::Atom;
use electron::ELECTRON;
use namings::{ion_superscript, number_to_roman};
use molecule::Molecule;
use trait_element::Element;
use trait_properties::Properties;
use types::*;

#[derive(Debug, Eq, PartialEq, Clone, Hash)]
/// An `Ion`
pub struct Ion {
    /// The molecule of this ion
    pub molecule: Molecule,

    /// The charge of this ion
    pub charge: Option<IonCharge>,
}

/// Get the charge an atom has based on its group
pub fn charge_of_atom(atom: &Atom) -> Option<IonCharge> {
    let group = atom.group;
    let number = atom.number;

    if group == 1 {
        Some(1)
    } else if group == 2 {
        Some(2)
    } else if group == 15 && number <= 15 {
        Some(-3)
    } else if group == 16 && number <= 34 {
        Some(-2)
    } else if group == 17 && number <= 53 {
        Some(-1)
    } else if group == 18 {
        Some(0)
    } else {
        None
    }
}

impl Ion {
    /// Convert a string representation of an `Ion` into one
    pub fn from_string(symbol: String) -> Option<Ion> {
        let mut molecule = None;
        let mut charge: IonCharge = 0;
        let mut is_negative = false;

        let mut token = String::new();
        let mut set_charge = false;

        for c in symbol.chars() {
            if c == ';' {
                // Electron
                if token == "e" {
                    return Some(ELECTRON.clone());
                }

                molecule = Molecule::from_string(token);
                token = String::new();
                set_charge = true;
                continue;
            }

            if set_charge {
                if c == '-' {
                    is_negative = true;
                    continue;
                }

                charge *= 10;
                charge += to_number!(c) as i8;
                continue;
            }

            token.push(c);
        }

        // It's just a molecule
        if !token.is_empty() && !set_charge {
            // Electron
            if token == "e" {
                return Some(ELECTRON.clone());
            }

            molecule = Molecule::from_string(token);
        }

        if is_negative {
            // assume - to mean -1
            if charge == 0 {
                charge = -1;
            } else {
                charge *= -1;
            }
        }

        if let Some(molecule) = molecule {
            Some(Ion {
                     molecule: molecule,
                     charge: Some(charge),
                 })
        } else {
            None
        }
    }

    /// Convert a `Molecule` into an `Ion`
    pub fn from_molecule(molecule: Molecule) -> Ion {
        Ion {
            molecule: molecule,
            charge: None, // Will be calculated later
        }
    }

    /// Calculate the charge of this `Ion`
    pub fn calculate_charge(&self) -> Option<IonCharge> {
        let mut charge = 0;

        for molecule_compound in &self.molecule.compounds {
            if let Some(atom_charge) = charge_of_atom(&molecule_compound.atom) {
                let mol_charge = (molecule_compound.amount as IonCharge) * atom_charge;

                charge += mol_charge;
            }
        }

        // HACK: This seems to be correct for now
        charge %= 8;

        Some(charge)
    }
}

impl Element for Ion {
    fn get_charge(&self) -> Option<IonCharge> {
        if let Some(charge) = self.charge {
            Some(charge)
        } else {
            self.calculate_charge()
        }
    }

    fn get_molecule(&self) -> Option<&Molecule> {
        Some(&self.molecule)
    }
}

impl Properties for Ion {
    fn symbol(&self) -> String {
        let mut symbol = String::new();

        symbol += &self.molecule.symbol();

        if let Some(charge) = self.get_charge() {
            if charge != 0 {
                symbol += &ion_superscript(charge);
            }
        }

        symbol
    }

    fn name(&self) -> String {
        let mut name = String::new();

        name += &self.molecule.name();

        if let Some(charge) = self.get_charge() {
            if charge != 0 {
                name += "(";
                name += &number_to_roman(charge);
                name += ")";
            }
        }

        name
    }

    fn mass(&self) -> AtomMass {
        self.molecule.mass()
    }
}
<commit_msg>Fixed order of converting string to ion<commit_after>use atom::Atom;
use electron::ELECTRON;
use namings::{ion_superscript, number_to_roman};
use molecule::Molecule;
use trait_element::Element;
use trait_properties::Properties;
use types::*;

#[derive(Debug, Eq, PartialEq, Clone, Hash)]
/// An `Ion`
pub struct Ion {
    /// The molecule of this ion
    pub molecule: Molecule,

    /// The charge of this ion
    pub charge: Option<IonCharge>,
}

/// Get the charge an atom has based on its group
pub fn charge_of_atom(atom: &Atom) -> Option<IonCharge> {
    let group = atom.group;
    let number = atom.number;

    if group == 1 {
        Some(1)
    } else if group == 2 {
        Some(2)
    } else if group == 15 && number <= 15 {
        Some(-3)
    } else if group == 16 && number <= 34 {
        Some(-2)
    } else if group == 17 && number <= 53 {
        Some(-1)
    } else if group == 18 {
        Some(0)
    } else {
        None
    }
}

impl Ion {
    /// Convert a string representation of an `Ion` into one
    pub fn from_string(symbol: String) -> Option<Ion> {
        let mut molecule = None;
        let mut charge: IonCharge = 0;
        let mut is_negative = false;

        let mut token = String::new();
        let mut set_charge = false;

        for c in symbol.chars() {
            if set_charge {
                if c == '-' {
                    is_negative = true;
                    continue;
                }

                if ! is_number!(c) {
                    return None;
                }

                charge *= 10;
                charge += to_number!(c) as i8;
                continue;
            }

            if c == ';' {
                // Electron
                if token == "e" {
                    return Some(ELECTRON.clone());
                }

                molecule = Molecule::from_string(token);
                token = String::new();
                set_charge = true;
                continue;
            }

            token.push(c);
        }

        // It's just a molecule
        if !token.is_empty() && !set_charge {
            // Electron
            if token == "e" {
                return Some(ELECTRON.clone());
            }

            molecule = Molecule::from_string(token);
        }

        if is_negative {
            // assume - to mean -1
            if charge == 0 {
                charge = -1;
            } else {
                charge *= -1;
            }
        }

        if let Some(molecule) = molecule {
            Some(Ion {
                     molecule: molecule,
                     charge: Some(charge),
                 })
        } else {
            None
        }
    }

    /// Convert a `Molecule` into an `Ion`
    pub fn from_molecule(molecule: Molecule) -> Ion {
        Ion {
            molecule: molecule,
            charge: None, // Will be calculated later
        }
    }

    /// Calculate the charge of this `Ion`
    pub fn calculate_charge(&self) -> Option<IonCharge> {
        let mut charge = 0;

        for molecule_compound in &self.molecule.compounds {
            if let Some(atom_charge) = charge_of_atom(&molecule_compound.atom) {
                let mol_charge = (molecule_compound.amount as IonCharge) * atom_charge;

                charge += mol_charge;
            }
        }

        // HACK: This seems to be correct for now
        charge %= 8;

        Some(charge)
    }
}

impl Element for Ion {
    fn get_charge(&self) -> Option<IonCharge> {
        if let Some(charge) = self.charge {
            Some(charge)
        } else {
            self.calculate_charge()
        }
    }

    fn get_molecule(&self) -> Option<&Molecule> {
        Some(&self.molecule)
    }
}

impl Properties for Ion {
    fn symbol(&self) -> String {
        let mut symbol = String::new();

        symbol += &self.molecule.symbol();

        if let Some(charge) = self.get_charge() {
            if charge != 0 {
                symbol += &ion_superscript(charge);
            }
        }

        symbol
    }

    fn name(&self) -> String {
        let mut name = String::new();

        name += &self.molecule.name();

        if let Some(charge) = self.get_charge() {
            if charge != 0 {
                name += "(";
                name += &number_to_roman(charge);
                name += ")";
            }
        }

        name
    }

    fn mass(&self) -> AtomMass {
        self.molecule.mass()
    }
}
<|endoftext|>


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

use parsers::ParseError;

#[derive(Debug)]
pub enum AttributeError {
    // parse error
    Parse (ParseError),

    // invalid value
    Value (String)
}

#[derive(Debug)]
pub struct NodeError {
    attr_name: &'static str,
    err:       AttributeError
}

impl NodeError {
    pub fn parse_error (attr_name: &'static str, error: ParseError) -> NodeError {
        NodeError {
            attr_name: attr_name,
            err: AttributeError::Parse (error)
        }
    }

    pub fn value_error (attr_name: &'static str, description: String) -> NodeError {
        NodeError {
            attr_name: attr_name,
            err: AttributeError::Value (description)
        }
    }
}

impl error::Error for NodeError {
    fn description (&self) -> &str {
        match self.err {
            AttributeError::Parse (ref n) => &"parse error",
            AttributeError::Value (_) => &"invalid attribute value"
        }
    }
}

impl fmt::Display for NodeError {
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.err {
            AttributeError::Parse (ref n) => write! (f,
                                                     "error parsing value for attribute \"{}\": {}",
                                                     self.attr_name,
                                                     n.display),

            AttributeError::Value (ref s) => write! (f,
                                                     "invalid value for attribute \"{}\": {}",
                                                     self.attr_name,
                                                     s)
        }
    }
}

<commit_msg>error.rs: Implement From<ParseError> for AttributeError<commit_after>use std::fmt;
use std::error;

use parsers::ParseError;

#[derive(Debug)]
pub enum AttributeError {
    // parse error
    Parse (ParseError),

    // invalid value
    Value (String)
}

#[derive(Debug)]
pub struct NodeError {
    attr_name: &'static str,
    err:       AttributeError
}

impl NodeError {
    pub fn parse_error (attr_name: &'static str, error: ParseError) -> NodeError {
        NodeError {
            attr_name: attr_name,
            err: AttributeError::Parse (error)
        }
    }

    pub fn value_error (attr_name: &'static str, description: String) -> NodeError {
        NodeError {
            attr_name: attr_name,
            err: AttributeError::Value (description)
        }
    }
}

impl error::Error for NodeError {
    fn description (&self) -> &str {
        match self.err {
            AttributeError::Parse (ref n) => &"parse error",
            AttributeError::Value (_) => &"invalid attribute value"
        }
    }
}

impl fmt::Display for NodeError {
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.err {
            AttributeError::Parse (ref n) => write! (f,
                                                     "error parsing value for attribute \"{}\": {}",
                                                     self.attr_name,
                                                     n.display),

            AttributeError::Value (ref s) => write! (f,
                                                     "invalid value for attribute \"{}\": {}",
                                                     self.attr_name,
                                                     s)
        }
    }
}

impl From<ParseError> for AttributeError {
    fn from (pe: ParseError) -> AttributeError {
        AttributeError::Parse (pe)
    }
}

pub fn is_parse_error<T> (r: &Result<T, AttributeError>) -> bool {
    if r.is_err () {
        match r.unwrap_err () {
            AttributeError::Parse (_) => true,
            _ => false
        }
    } else {
        false
    }
}

pub fn is_value_error<T> (r: &Result<T, AttributeError>) -> bool {
    if r.is_err () {
        match r.unwrap_err () {
            AttributeError::Value (_) => true,
            _ => false
        }
    } else {
        false
    }
}
<|endoftext|>


<commit_before>use std::iter;
use std::mem;
use std::slice;

/// A parsing error, with location information.
#[deriving(Show, PartialEq)]
pub struct ParseError {
  /// The line of input the error is on.
  pub line_number:   uint,
  /// The error message.
  pub message:       String,
}

#[inline]
fn c2u8(c: char) -> u8 {
  c as u8
}

#[allow(dead_code)]
fn s2u8(s: &str) -> Vec<u8> {
  s.bytes().collect()
}

#[allow(dead_code)]
fn u82s<'a>(u8s: &'a [u8]) -> &'a str {
  // According to the docs, &'a str is the same representation as a &'a [u8].
  unsafe { mem::transmute(u8s) }
}

#[test]
fn verify_u82s() {
  let cases = [ "hello", "world" ];

  for &case in cases.iter() {
    assert_eq!(u82s(s2u8(case).as_slice()), case);
  }
}

#[inline]
fn is_whitespace(c: u8) -> bool {
  c == c2u8(' ') || c == c2u8('\t') || c == c2u8('\n')
}

pub struct Lexer<'a> {
  bytes: iter::Peekable<u8, iter::Fuse<iter::Map<'a, &'a u8, u8, slice::Items<'a, u8>>>>,
  current_line_number: uint,
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Lexer<'a> {
    Lexer {
      bytes: input.bytes().fuse().peekable(),
      current_line_number: 1,
    }
  }

  /// Advance the lexer by one character.
  fn advance(&mut self) {
    match self.bytes.next() {
      None => {},
      Some(c) => {
        if c == c2u8('\n') {
          self.current_line_number += 1;
        }
      }
    }
  }

  /// Looks at the next character the lexer is pointing to.
  fn peek(&mut self) -> Option<u8> {
    self.bytes.peek().map(|c| *c)
  }

  /// Advance past characters until the given condition is true.
  ///
  /// Returns whether or not any of the input was skipped.
  ///
  /// Postcondition: Either the end of the input was reached or
  /// `is_true` returns false for the currently peekable character.
  fn skip_while(&mut self, is_true: |u8| -> bool) -> bool {
    let mut was_anything_skipped = false;

    loop {
      match self.peek() {
        None => break,
        Some(c) => {
          if !is_true(c) { break }
        }
      }
      self.advance();
      was_anything_skipped = true;
    }

    debug_assert!(self.peek().map(|c| !is_true(c)).unwrap_or(true));

    was_anything_skipped
  }

  /// Advance past characters until the given condition is true.
  ///
  /// Returns whether or not any of the input was skipped.
  ///
  /// Postcondition: Either the end of the input was reached or
  /// `is_false` returns true for the currently peekable character.
  fn skip_unless(&mut self, is_false: |u8| -> bool) -> bool {
    self.skip_while(|c| !is_false(c))
  }

  /// Advances past comments in the input, including their trailing newlines.
  ///
  /// Returns whether or not any of the input was skipped.
  fn skip_comment(&mut self) -> bool {
    match self.peek() {
      None => return false,
      Some(c) => {
        if c == c2u8('#') {
          // skip over the rest of the comment (except the newline)
          self.skip_unless(|c| c == c2u8('\n'));
          return true;
        } else {
          return false;
        }
      }
    }
  }

  fn skip_whitespace_except_newline(&mut self) -> bool {
    self.skip_while(|c| c == c2u8('\t') || c == c2u8(' '))
  }

  /// Gets the next word in the input, as well as whether it's on
  /// a different line than the last word we got.
  fn next_word(&mut self) -> Option<Vec<u8>> {
    let mut ret: Vec<u8> = Vec::new();

    self.skip_whitespace_except_newline();

    loop {
      match self.peek() {
        None => break,
        Some(c) => {
          if c == c2u8('#') {
            assert!(self.skip_comment());
            self.skip_whitespace_except_newline();
          } else if is_whitespace(c) {
            if c == c2u8('\n') && ret.is_empty() {
              ret.push(c);
              self.advance();
            }
            break;
          } else {
            ret.push(c);
            self.advance();
          }
        }
      }
    }

    if ret.is_empty() {
      debug_assert_eq!(self.peek(), None);
      None
    } else {
      Some(ret)
    }
  }
}

impl<'a> Iterator<String> for Lexer<'a> {
  fn next(&mut self) -> Option<String> {
    match self.next_word() {
      None => None,
      Some(buf) => {
        match String::from_utf8(buf) {
          Ok(s) => Some(s),
          Err(_) => fail!("Lex error: Invalid utf8 on line {}.", self.current_line_number),
        }
      }
    }
  }

  fn size_hint(&self) -> (uint, Option<uint>) {
    (0, None)
  }
}

#[test]
fn test_next_word() {
  let mut l = Lexer::new("hello world\n this# is\na   \t test\n");
  assert_eq!(l.next_word(), Some(s2u8("hello")));
  assert_eq!(l.current_line_number, 1);
  assert_eq!(l.next_word(), Some(s2u8("world")));
  assert_eq!(l.current_line_number, 1);
  assert_eq!(l.next_word(), Some(s2u8("\n")));
  assert_eq!(l.current_line_number, 2);
  assert_eq!(l.next_word(), Some(s2u8("this")));
  assert_eq!(l.current_line_number, 2);
  assert_eq!(l.next_word(), Some(s2u8("\n")));
  assert_eq!(l.current_line_number, 3);
  assert_eq!(l.next_word(), Some(s2u8("a")));
  assert_eq!(l.current_line_number, 3);
  assert_eq!(l.next_word(), Some(s2u8("test")));
  assert_eq!(l.current_line_number, 3);
  assert_eq!(l.next_word(), Some(s2u8("\n")));
  assert_eq!(l.current_line_number, 4);
  assert_eq!(l.next_word(), None);
}

#[test]
fn test_simd() {
  use std::simd;

  let x = simd::f32x4(1.0,2.0,3.0,4.0);

  let simd::f32x4(a, b, c, d) = x;

  assert_eq!(a, 1.0);
  assert_eq!(b, 2.0);
  assert_eq!(c, 3.0);
  assert_eq!(d, 4.0);
}
<commit_msg>wtf simd get outta here<commit_after>use std::iter;
use std::mem;
use std::slice;

/// A parsing error, with location information.
#[deriving(Show, PartialEq)]
pub struct ParseError {
  /// The line of input the error is on.
  pub line_number:   uint,
  /// The error message.
  pub message:       String,
}

#[inline]
fn c2u8(c: char) -> u8 {
  c as u8
}

#[allow(dead_code)]
fn s2u8(s: &str) -> Vec<u8> {
  s.bytes().collect()
}

#[allow(dead_code)]
fn u82s<'a>(u8s: &'a [u8]) -> &'a str {
  // According to the docs, &'a str is the same representation as a &'a [u8].
  unsafe { mem::transmute(u8s) }
}

#[test]
fn verify_u82s() {
  let cases = [ "hello", "world" ];

  for &case in cases.iter() {
    assert_eq!(u82s(s2u8(case).as_slice()), case);
  }
}

#[inline]
fn is_whitespace(c: u8) -> bool {
  c == c2u8(' ') || c == c2u8('\t') || c == c2u8('\n')
}

pub struct Lexer<'a> {
  bytes: iter::Peekable<u8, iter::Fuse<iter::Map<'a, &'a u8, u8, slice::Items<'a, u8>>>>,
  current_line_number: uint,
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Lexer<'a> {
    Lexer {
      bytes: input.bytes().fuse().peekable(),
      current_line_number: 1,
    }
  }

  /// Advance the lexer by one character.
  fn advance(&mut self) {
    match self.bytes.next() {
      None => {},
      Some(c) => {
        if c == c2u8('\n') {
          self.current_line_number += 1;
        }
      }
    }
  }

  /// Looks at the next character the lexer is pointing to.
  fn peek(&mut self) -> Option<u8> {
    self.bytes.peek().map(|c| *c)
  }

  /// Advance past characters until the given condition is true.
  ///
  /// Returns whether or not any of the input was skipped.
  ///
  /// Postcondition: Either the end of the input was reached or
  /// `is_true` returns false for the currently peekable character.
  fn skip_while(&mut self, is_true: |u8| -> bool) -> bool {
    let mut was_anything_skipped = false;

    loop {
      match self.peek() {
        None => break,
        Some(c) => {
          if !is_true(c) { break }
        }
      }
      self.advance();
      was_anything_skipped = true;
    }

    debug_assert!(self.peek().map(|c| !is_true(c)).unwrap_or(true));

    was_anything_skipped
  }

  /// Advance past characters until the given condition is true.
  ///
  /// Returns whether or not any of the input was skipped.
  ///
  /// Postcondition: Either the end of the input was reached or
  /// `is_false` returns true for the currently peekable character.
  fn skip_unless(&mut self, is_false: |u8| -> bool) -> bool {
    self.skip_while(|c| !is_false(c))
  }

  /// Advances past comments in the input, including their trailing newlines.
  ///
  /// Returns whether or not any of the input was skipped.
  fn skip_comment(&mut self) -> bool {
    match self.peek() {
      None => return false,
      Some(c) => {
        if c == c2u8('#') {
          // skip over the rest of the comment (except the newline)
          self.skip_unless(|c| c == c2u8('\n'));
          return true;
        } else {
          return false;
        }
      }
    }
  }

  fn skip_whitespace_except_newline(&mut self) -> bool {
    self.skip_while(|c| c == c2u8('\t') || c == c2u8(' '))
  }

  /// Gets the next word in the input, as well as whether it's on
  /// a different line than the last word we got.
  fn next_word(&mut self) -> Option<Vec<u8>> {
    let mut ret: Vec<u8> = Vec::new();

    self.skip_whitespace_except_newline();

    loop {
      match self.peek() {
        None => break,
        Some(c) => {
          if c == c2u8('#') {
            assert!(self.skip_comment());
            self.skip_whitespace_except_newline();
          } else if is_whitespace(c) {
            if c == c2u8('\n') && ret.is_empty() {
              ret.push(c);
              self.advance();
            }
            break;
          } else {
            ret.push(c);
            self.advance();
          }
        }
      }
    }

    if ret.is_empty() {
      debug_assert_eq!(self.peek(), None);
      None
    } else {
      Some(ret)
    }
  }
}

impl<'a> Iterator<String> for Lexer<'a> {
  fn next(&mut self) -> Option<String> {
    match self.next_word() {
      None => None,
      Some(buf) => {
        match String::from_utf8(buf) {
          Ok(s) => Some(s),
          Err(_) => fail!("Lex error: Invalid utf8 on line {}.", self.current_line_number),
        }
      }
    }
  }

  fn size_hint(&self) -> (uint, Option<uint>) {
    (0, None)
  }
}

#[test]
fn test_next_word() {
  let mut l = Lexer::new("hello world\n this# is\na   \t test\n");
  assert_eq!(l.next_word(), Some(s2u8("hello")));
  assert_eq!(l.current_line_number, 1);
  assert_eq!(l.next_word(), Some(s2u8("world")));
  assert_eq!(l.current_line_number, 1);
  assert_eq!(l.next_word(), Some(s2u8("\n")));
  assert_eq!(l.current_line_number, 2);
  assert_eq!(l.next_word(), Some(s2u8("this")));
  assert_eq!(l.current_line_number, 2);
  assert_eq!(l.next_word(), Some(s2u8("\n")));
  assert_eq!(l.current_line_number, 3);
  assert_eq!(l.next_word(), Some(s2u8("a")));
  assert_eq!(l.current_line_number, 3);
  assert_eq!(l.next_word(), Some(s2u8("test")));
  assert_eq!(l.current_line_number, 3);
  assert_eq!(l.next_word(), Some(s2u8("\n")));
  assert_eq!(l.current_line_number, 4);
  assert_eq!(l.next_word(), None);
}
<|endoftext|>


<commit_before>//! Parser for bitmap fonts

#![feature(unicode)]

mod char;
mod config_parse_error;
mod error;
mod kerning_value;
mod page;
mod rect;
mod sections;
mod string_parse_error;
mod utils;

pub use self::config_parse_error::ConfigParseError;
pub use self::error::Error;
pub use self::rect::Rect;
pub use self::string_parse_error::StringParseError;

use std::io::Read;
use self::char::Char;
use self::kerning_value::KerningValue;
use self::page::Page;
use self::sections::Sections;

pub struct CharPosition {
    pub page_rect: Rect,
    pub screen_rect: Rect,
    pub page_index: u32,
}

pub enum OrdinateOrientation {
    BottomToTop,
    TopToBottom,
}

pub struct BMFont {
    base_height: u32,
    line_height: u32,
    characters: Vec<Char>,
    kerning_values: Vec<KerningValue>,
    pages: Vec<Page>,
    ordinate_orientation: OrdinateOrientation,
}

impl BMFont {
    pub fn new<R>(source: R, ordinate_orientation: OrdinateOrientation) -> Result<BMFont, Error>
        where R: Read
    {
        let sections = try!(Sections::new(source));

        let base_height;
        let line_height;
        {
            let mut components = sections.common_section.split_whitespace();
            components.next();
            line_height = try!(utils::extract_component_value(components.next(), "common", "lineHeight"));
            base_height = try!(utils::extract_component_value(components.next(), "common", "base"));
        }

        let mut pages = Vec::new();
        for page_section in &sections.page_sections {
            pages.push(try!(Page::new(page_section)));
        }
        let mut characters = Vec::new();
        for char_section in &sections.char_sections {
            characters.push(try!(Char::new(char_section)));
        }
        let mut kerning_values = Vec::new();
        for kerning_section in &sections.kerning_sections {
            kerning_values.push(try!(KerningValue::new(kerning_section)));
        }
        Ok(BMFont {
            base_height: base_height,
            line_height: line_height,
            characters: characters,
            kerning_values: kerning_values,
            pages: pages,
            ordinate_orientation: ordinate_orientation,
        })
    }

    /// Returns the height of a `EM` in pixels.
    pub fn base_height(&self) -> u32 {
        self.base_height
    }

    pub fn line_height(&self) -> u32 {
        self.line_height
    }

    pub fn pages(&self) -> Vec<String> {
        self.pages.iter().map(|p| p.file.clone()).collect()
    }

    pub fn parse(&self, s: &str) -> Result<Vec<CharPosition>, StringParseError> {
        let lines = try!(self.parse_lines(s));
        let mut char_positions = Vec::new();
        let mut y: i32 = 0;
        for line in lines {
            let mut x: i32 = 0;
            let mut kerning_values: Vec<&KerningValue> = Vec::new();
            for character in line {
                let kerning_value = kerning_values.into_iter()
                                                  .find(|k| k.second_char_id == character.id)
                                                  .map(|k| k.value)
                                                  .unwrap_or(0);
                let page_rect = Rect {
                    x: character.x as i32,
                    y: character.y as i32,
                    width: character.width,
                    height: character.height,
                };
                let screen_x = x + character.xoffset + kerning_value;
                let screen_y = match self.ordinate_orientation {
                    OrdinateOrientation::BottomToTop => {
                        y + self.line_height as i32 - character.yoffset - character.height as i32
                    }
                    OrdinateOrientation::TopToBottom => y + character.yoffset,
                };
                let screen_rect = Rect {
                    x: screen_x,
                    y: screen_y,
                    width: character.width,
                    height: character.height,
                };
                let char_position = CharPosition {
                    page_rect: page_rect,
                    screen_rect: screen_rect,
                    page_index: character.page_index,
                };
                char_positions.push(char_position);
                x += character.xadvance + kerning_value;
                kerning_values = self.find_kerning_values(character.id);
            }
            match self.ordinate_orientation {
                OrdinateOrientation::TopToBottom => y += self.line_height as i32,
                OrdinateOrientation::BottomToTop => y -= self.line_height as i32,
            }
        }
        Ok(char_positions)
    }

    fn find_kerning_values(&self, first_char_id: u32) -> Vec<&KerningValue> {
        self.kerning_values.iter().filter(|k| k.first_char_id == first_char_id).collect()
    }

    fn parse_lines(&self, s: &str) -> Result<Vec<Vec<&Char>>, StringParseError> {
        let mut lines = Vec::new();
        let mut line = Vec::new();
        let mut missing_characters = Vec::new();
        let mut unsupported_characters = Vec::new();
        for c in s.chars() {
            if c == '\n' {
                lines.push(line);
                line = Vec::new();
                continue;
            }
            if c.len_utf16() != 1 {
                unsupported_characters.push(c);
                continue;
            }
            let mut buffer: [u16; 4] = [0, 0, 0, 0];
            c.encode_utf16(&mut buffer).unwrap();
            let char_id = buffer[0] as u32;
            if let Some(c) = self.characters.iter().find(|c| c.id == char_id) {
                line.push(c);
            } else {
                missing_characters.push(c);
            }
        }
        if !line.is_empty() {
            lines.push(line);
        }
        if missing_characters.is_empty() && unsupported_characters.is_empty() {
            Ok(lines)
        } else {
            Err(StringParseError {
                missing_characters: missing_characters,
                unsupported_characters: unsupported_characters,
            })
        }
    }
}
<commit_msg>Fix position calculation<commit_after>//! Parser for bitmap fonts

#![feature(unicode)]

mod char;
mod config_parse_error;
mod error;
mod kerning_value;
mod page;
mod rect;
mod sections;
mod string_parse_error;
mod utils;

pub use self::config_parse_error::ConfigParseError;
pub use self::error::Error;
pub use self::rect::Rect;
pub use self::string_parse_error::StringParseError;

use std::io::Read;
use self::char::Char;
use self::kerning_value::KerningValue;
use self::page::Page;
use self::sections::Sections;

pub struct CharPosition {
    pub page_rect: Rect,
    pub screen_rect: Rect,
    pub page_index: u32,
}

pub enum OrdinateOrientation {
    BottomToTop,
    TopToBottom,
}

pub struct BMFont {
    base_height: u32,
    line_height: u32,
    characters: Vec<Char>,
    kerning_values: Vec<KerningValue>,
    pages: Vec<Page>,
    ordinate_orientation: OrdinateOrientation,
}

impl BMFont {
    pub fn new<R>(source: R, ordinate_orientation: OrdinateOrientation) -> Result<BMFont, Error>
        where R: Read
    {
        let sections = try!(Sections::new(source));

        let base_height;
        let line_height;
        {
            let mut components = sections.common_section.split_whitespace();
            components.next();
            line_height = try!(utils::extract_component_value(components.next(), "common", "lineHeight"));
            base_height = try!(utils::extract_component_value(components.next(), "common", "base"));
        }

        let mut pages = Vec::new();
        for page_section in &sections.page_sections {
            pages.push(try!(Page::new(page_section)));
        }
        let mut characters = Vec::new();
        for char_section in &sections.char_sections {
            characters.push(try!(Char::new(char_section)));
        }
        let mut kerning_values = Vec::new();
        for kerning_section in &sections.kerning_sections {
            kerning_values.push(try!(KerningValue::new(kerning_section)));
        }
        Ok(BMFont {
            base_height: base_height,
            line_height: line_height,
            characters: characters,
            kerning_values: kerning_values,
            pages: pages,
            ordinate_orientation: ordinate_orientation,
        })
    }

    /// Returns the height of a `EM` in pixels.
    pub fn base_height(&self) -> u32 {
        self.base_height
    }

    pub fn line_height(&self) -> u32 {
        self.line_height
    }

    pub fn pages(&self) -> Vec<String> {
        self.pages.iter().map(|p| p.file.clone()).collect()
    }

    pub fn parse(&self, s: &str) -> Result<Vec<CharPosition>, StringParseError> {
        let lines = try!(self.parse_lines(s));
        let mut char_positions = Vec::new();
        let mut y: i32 = 0;
        for line in lines {
            let mut x: i32 = 0;
            let mut kerning_values: Vec<&KerningValue> = Vec::new();
            for character in line {
                let kerning_value = kerning_values.into_iter()
                                                  .find(|k| k.second_char_id == character.id)
                                                  .map(|k| k.value)
                                                  .unwrap_or(0);
                let page_rect = Rect {
                    x: character.x as i32,
                    y: character.y as i32,
                    width: character.width,
                    height: character.height,
                };
                let screen_x = x + character.xoffset + kerning_value;
                let screen_y = match self.ordinate_orientation {
                    OrdinateOrientation::BottomToTop => {
                        y + self.base_height as i32 - character.yoffset - character.height as i32
                    }
                    OrdinateOrientation::TopToBottom => y + character.yoffset,
                };
                let screen_rect = Rect {
                    x: screen_x,
                    y: screen_y,
                    width: character.width,
                    height: character.height,
                };
                let char_position = CharPosition {
                    page_rect: page_rect,
                    screen_rect: screen_rect,
                    page_index: character.page_index,
                };
                char_positions.push(char_position);
                x += character.xadvance + kerning_value;
                kerning_values = self.find_kerning_values(character.id);
            }
            match self.ordinate_orientation {
                OrdinateOrientation::TopToBottom => y += self.line_height as i32,
                OrdinateOrientation::BottomToTop => y -= self.line_height as i32,
            }
        }
        Ok(char_positions)
    }

    fn find_kerning_values(&self, first_char_id: u32) -> Vec<&KerningValue> {
        self.kerning_values.iter().filter(|k| k.first_char_id == first_char_id).collect()
    }

    fn parse_lines(&self, s: &str) -> Result<Vec<Vec<&Char>>, StringParseError> {
        let mut lines = Vec::new();
        let mut line = Vec::new();
        let mut missing_characters = Vec::new();
        let mut unsupported_characters = Vec::new();
        for c in s.chars() {
            if c == '\n' {
                lines.push(line);
                line = Vec::new();
                continue;
            }
            if c.len_utf16() != 1 {
                unsupported_characters.push(c);
                continue;
            }
            let mut buffer: [u16; 4] = [0, 0, 0, 0];
            c.encode_utf16(&mut buffer).unwrap();
            let char_id = buffer[0] as u32;
            if let Some(c) = self.characters.iter().find(|c| c.id == char_id) {
                line.push(c);
            } else {
                missing_characters.push(c);
            }
        }
        if !line.is_empty() {
            lines.push(line);
        }
        if missing_characters.is_empty() && unsupported_characters.is_empty() {
            Ok(lines)
        } else {
            Err(StringParseError {
                missing_characters: missing_characters,
                unsupported_characters: unsupported_characters,
            })
        }
    }
}
<|endoftext|>


<commit_before>extern crate time;
use time::precise_time_ns;

pub fn time_ns() -> u64 {
    precise_time_ns()
}

#[macro_export]
macro_rules! stack {
    ($name:expr, $work:expr) => {
        {
            let work = {|| $work};
            println!("Push {}", $name);
            let before = $crate::time_ns();
            let value = work();
            let after = $crate::time_ns();
            println!("Pop {} spent {}ns.", $name, after-before);
            value
        }
    }
}

#[test]
fn it_works() {
    stack!("all", 3+4);
}
<commit_msg>When work is a closure, it needs to be able to change.<commit_after>extern crate time;
use time::precise_time_ns;

pub fn time_ns() -> u64 {
    precise_time_ns()
}

#[macro_export]
macro_rules! stack {
    ($name:expr, $work:expr) => {
        {
            let mut work = {|| $work};
            println!("Push {}", $name);
            let before = $crate::time_ns();
            let value = work();
            let after = $crate::time_ns();
            println!("Pop {} spent {}ns.", $name, after-before);
            value
        }
    }
}

#[test]
fn it_works() {
    stack!("all", 3+4);
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://urschrei.github.io/polyline-ffi/")]
//! This module exposes functions for accessing the Polyline encoding and decoding functions via FFI
extern crate polyline;
use polyline::{encode_coordinates, decode_polyline};
use std::mem;
use std::slice;
use std::f64;
use std::ffi::{CStr, CString};

extern crate libc;
use self::libc::{c_char, c_void, uint32_t, size_t};

#[repr(C)]
pub struct Array {
    pub data: *const c_void,
    pub len: size_t,
}

// Build an Array from &[[f64; 2]], so it can be leaked across the FFI boundary
impl<'a> From<&'a [[f64; 2]]> for Array {
    fn from(sl: &'a [[f64; 2]]) -> Self {
        let array = Array {
            data: sl.as_ptr() as *const c_void,
            len: sl.len() as size_t,
        };
        mem::forget(sl);
        array
    }
}

// Build &[[f64; 2]] from an Array, so it can be dropped
impl<'a> From<Array> for &'a [[f64; 2]] {
    fn from(arr: Array) -> Self {
        unsafe { slice::from_raw_parts(arr.data as *const [f64; 2], arr.len) }
    }
}

// Decode a Polyline into an Array
fn arr_from_string(incoming: String, precision: uint32_t) -> Array {
    let result: Array = match decode_polyline(incoming, precision) {
        Ok(res) => res.as_slice().into(),
        // should be easy to check for
        Err(_) => vec![[f64::NAN, f64::NAN]].as_slice().into(),
    };
    result.into()
}

// Decode an Array into a Polyline
fn string_from_arr(incoming: Array, precision: uint32_t) -> String {
    match encode_coordinates(incoming.into(), precision) {
        Ok(res) => res,
        // we don't need to adapt the error
        Err(res) => res,
    }
}

/// Convert a Polyline into an array of coordinates
///
/// Callers must pass two arguments:
///
/// - a pointer to `NUL`-terminated characters (`char*`)
/// - an unsigned 32-bit `int` for precision (5 for Google Polylines, 6 for
/// OSRM and Valhalla Polylines)
///
/// # Examples
///
/// ```
/// use std::ffi::CString;
/// use std::slice;
/// let input = CString::new("_ibE_seK_seK_seK").unwrap().as_ptr();
/// let result: Array = decode_polyline_ffi(input, 5);
/// let slice = unsafe { slice::from_raw_parts(result.data as *const [f64; 2], result.len) };
/// assert_eq!(slice, [[1.0, 2.0], [3.0, 4.0]]);
/// drop_float_array(result);
/// ```
///
/// A decoding failure will always return an array: `[[NaN, NaN]]`
///
/// Implementations calling this function **must** call [`drop_float_array`](fn.drop_float_array.html)
/// with the returned [Array](struct.Array.html), in order to free the memory it allocates.
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn decode_polyline_ffi(pl: *const c_char, precision: uint32_t) -> Array {
    let s: String = unsafe { CStr::from_ptr(pl).to_string_lossy().into_owned() };
    arr_from_string(s, precision)
}

/// Convert an array of coordinates into a Polyline
///
/// Callers must pass two arguments:
///
/// - a [Struct](struct.Array.html) with two fields:
///     - `data`, a void pointer to an array of floating-point lat, lon coordinates: `[[1.0, 2.0]]`
///     - `len`, the length of the array being passed. Its type must be `size_t`: `1`
/// - an unsigned 32-bit `int` for precision (5 for Google Polylines, 6 for
/// OSRM and Valhalla Polylines)
///
/// # Examples
///
/// ```
/// extern crate libc;
/// use libc::{c_void, size_t};
/// use std::ffi::CStr;
/// use std::slice;
/// let input = vec![[1.0, 2.0], [3.0, 4.0]].as_slice();
/// let array = Array { data: input.as_ptr() as *const c_void, len: input.len() as size_t };
/// let output = "_ibE_seK_seK_seK".to_string();
/// let pl = encode_coordinates_ffi(array, 5);
/// let result = unsafe { CStr::from_ptr(pl).to_str().unwrap() };
/// assert_eq!(result, output);
/// drop_cstring(pl);
/// ```
///
/// A decoding failure will always return a string: "Couldn't decode Polyline"
///
/// Implementations calling this function **must** call [`drop_cstring`](fn.drop_cstring.html)
/// with the returned `c_char` pointer, in order to free the memory it allocates.
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn encode_coordinates_ffi(coords: Array, precision: uint32_t) -> *mut c_char {
    let s: String = string_from_arr(coords, precision);
    match CString::new(s) {
        Ok(res) => res.into_raw(),
        // It's arguably better to fail noisily, but this is robust
        Err(_) => CString::new("Couldn't decode Polyline".to_string()).unwrap().into_raw(),
    }
}

/// Free Array memory which Rust has allocated across the FFI boundary
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn drop_float_array(arr: Array) {
    if arr.data.is_null() {
        return;
    }
    let _: &[[f64; 2]] = arr.into();
}

/// Free `CString` memory which Rust has allocated across the FFI boundary
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn drop_cstring(p: *mut c_char) {
    let _ = unsafe { CString::from_raw(p) };
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ptr;
    use std::ffi::{CString, CStr};

    #[test]
    fn test_array_conversion() {
        let original = vec![[1.0, 2.0], [3.0, 4.0]];
        // move into an Array, and leak it
        let arr: Array = original.as_slice().into();
        // move back into a Vec -- leaked value still needs to be dropped
        let converted: &[[f64; 2]] = arr.into();
        assert_eq!(converted[0], [1.0, 2.0]);
        // drop it
        drop_float_array(converted.into());
    }

    #[test]
    fn test_drop_empty_float_array() {
        let original = vec![[1.0, 2.0], [3.0, 4.0]];
        // move into an Array, and leak it
        let mut arr: Array = original.as_slice().into();
        // zero Array contents
        arr.data = ptr::null();
        drop_float_array(arr);
    }

    #[test]
    fn test_coordinate_conversion() {
        let input = vec![[1.0, 2.0], [3.0, 4.0]];
        let output = "_ibE_seK_seK_seK";
        let input_arr: Array = input.as_slice().into();
        let transformed: String = super::string_from_arr(input_arr, 5);
        assert_eq!(transformed, output);
    }

    #[test]
    fn test_string_conversion() {
        let input = "_ibE_seK_seK_seK".to_string();
        let output = [[1.0, 2.0], [3.0, 4.0]];
        // String to Array
        let transformed: Array = super::arr_from_string(input, 5);
        // Array to Vec
        let transformed_arr: &[[f64; 2]] = transformed.into();
        assert_eq!(transformed_arr, output);
    }

    #[test]
    #[should_panic]
    fn test_bad_string_conversion() {
        let input = "_p~iF~ps|U_u🗑lLnnqC_mqNvxq`@".to_string();
        let output = vec![[1.0, 2.0], [3.0, 4.0]];
        // String to Array
        let transformed: Array = super::arr_from_string(input, 5);
        // Array to Vec
        let transformed_arr: &[[f64; 2]] = transformed.into();
        // this will fail, bc transformed_arr is [[NaN, NaN]]
        assert_eq!(transformed_arr, output.as_slice());
    }

    #[test]
    fn test_ffi_polyline_decoding() {
        let input = CString::new("_ibE_seK_seK_seK").unwrap().as_ptr();
        let result: &[[f64; 2]] = decode_polyline_ffi(input, 5).into();
        assert_eq!(result, [[1.0, 2.0], [3.0, 4.0]]);
        drop_float_array(result.into());
    }

    #[test]
    fn test_ffi_coordinate_encoding() {
        let input: Array = vec![[1.0, 2.0], [3.0, 4.0]].as_slice().into();
        let output = "_ibE_seK_seK_seK".to_string();
        let pl = encode_coordinates_ffi(input, 5);
        // Allocate a new String
        let result = unsafe { CStr::from_ptr(pl).to_str().unwrap() };
        assert_eq!(result, output);
        // Drop received FFI data
        drop_cstring(pl);
    }
}
<commit_msg>Fiddling with tests<commit_after>#![doc(html_root_url = "https://urschrei.github.io/polyline-ffi/")]
//! This module exposes functions for accessing the Polyline encoding and decoding functions via FFI
extern crate polyline;
use polyline::{encode_coordinates, decode_polyline};
use std::mem;
use std::slice;
use std::f64;
use std::ffi::{CStr, CString};

extern crate libc;
use self::libc::{c_char, c_void, uint32_t, size_t};

#[repr(C)]
pub struct Array {
    pub data: *const c_void,
    pub len: size_t,
}

// Build an Array from &[[f64; 2]], so it can be leaked across the FFI boundary
impl<'a> From<&'a [[f64; 2]]> for Array {
    fn from(sl: &'a [[f64; 2]]) -> Self {
        let array = Array {
            data: sl.as_ptr() as *const c_void,
            len: sl.len() as size_t,
        };
        mem::forget(sl);
        array
    }
}

// Build &[[f64; 2]] from an Array, so it can be dropped
impl<'a> From<Array> for &'a [[f64; 2]] {
    fn from(arr: Array) -> Self {
        unsafe { slice::from_raw_parts(arr.data as *const [f64; 2], arr.len) }
    }
}

// Decode a Polyline into an Array
fn arr_from_string(incoming: String, precision: uint32_t) -> Array {
    let result: Array = match decode_polyline(incoming, precision) {
        Ok(res) => res.as_slice().into(),
        // should be easy to check for
        Err(_) => vec![[f64::NAN, f64::NAN]].as_slice().into(),
    };
    result.into()
}

// Decode an Array into a Polyline
fn string_from_arr(incoming: Array, precision: uint32_t) -> String {
    match encode_coordinates(incoming.into(), precision) {
        Ok(res) => res,
        // we don't need to adapt the error
        Err(res) => res,
    }
}

/// Convert a Polyline into an array of coordinates
///
/// Callers must pass two arguments:
///
/// - a pointer to `NUL`-terminated characters (`char*`)
/// - an unsigned 32-bit `int` for precision (5 for Google Polylines, 6 for
/// OSRM and Valhalla Polylines)
///
/// # Examples
///
/// ```
/// use std::ffi::CString;
/// use std::slice;
/// let input = CString::new("_ibE_seK_seK_seK").unwrap().as_ptr();
/// let result: Array = decode_polyline_ffi(input, 5);
/// let slice = unsafe { slice::from_raw_parts(result.data as *const [f64; 2], result.len) };
/// assert_eq!(slice, [[1.0, 2.0], [3.0, 4.0]]);
/// drop_float_array(result);
/// ```
///
/// A decoding failure will always return an array: `[[NaN, NaN]]`
///
/// Implementations calling this function **must** call [`drop_float_array`](fn.drop_float_array.html)
/// with the returned [Array](struct.Array.html), in order to free the memory it allocates.
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn decode_polyline_ffi(pl: *const c_char, precision: uint32_t) -> Array {
    let s: String = unsafe { CStr::from_ptr(pl).to_string_lossy().into_owned() };
    arr_from_string(s, precision)
}

/// Convert an array of coordinates into a Polyline
///
/// Callers must pass two arguments:
///
/// - a [Struct](struct.Array.html) with two fields:
///     - `data`, a void pointer to an array of floating-point lat, lon coordinates: `[[1.0, 2.0]]`
///     - `len`, the length of the array being passed. Its type must be `size_t`: `1`
/// - an unsigned 32-bit `int` for precision (5 for Google Polylines, 6 for
/// OSRM and Valhalla Polylines)
///
/// # Examples
///
/// ```
/// extern crate libc;
/// use libc::{c_void, size_t};
/// use std::ffi::CStr;
/// use std::slice;
/// let input = vec![[1.0, 2.0], [3.0, 4.0]].as_slice();
/// let array = Array { data: input.as_ptr() as *const c_void, len: input.len() as size_t };
/// let output = "_ibE_seK_seK_seK".to_string();
/// let pl = encode_coordinates_ffi(array, 5);
/// let result = unsafe { CStr::from_ptr(pl).to_str().unwrap() };
/// assert_eq!(result, output);
/// drop_cstring(pl);
/// ```
///
/// A decoding failure will always return a string: "Couldn't decode Polyline"
///
/// Implementations calling this function **must** call [`drop_cstring`](fn.drop_cstring.html)
/// with the returned `c_char` pointer, in order to free the memory it allocates.
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn encode_coordinates_ffi(coords: Array, precision: uint32_t) -> *mut c_char {
    let s: String = string_from_arr(coords, precision);
    match CString::new(s) {
        Ok(res) => res.into_raw(),
        // It's arguably better to fail noisily, but this is robust
        Err(_) => CString::new("Couldn't decode Polyline".to_string()).unwrap().into_raw(),
    }
}

/// Free Array memory which Rust has allocated across the FFI boundary
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn drop_float_array(arr: Array) {
    if arr.data.is_null() {
        return;
    }
    let _: &[[f64; 2]] = arr.into();
}

/// Free `CString` memory which Rust has allocated across the FFI boundary
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn drop_cstring(p: *mut c_char) {
    let _ = unsafe { CString::from_raw(p) };
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ptr;
    use std::ffi::{CString, CStr};

    #[test]
    fn test_array_conversion() {
        let original = vec![[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]];
        // move into an Array, and leak it
        let arr: Array = original.as_slice().into();
        // move back into an slice -- leaked value still needs to be dropped
        let converted: &[[f64; 2]] = arr.into();
        assert_eq!(converted, &[[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]);
        // drop it
        drop_float_array(converted.into());
    }

    #[test]
    fn test_drop_empty_float_array() {
        let original = vec![[1.0, 2.0], [3.0, 4.0]];
        // move into an Array, and leak it
        let mut arr: Array = original.as_slice().into();
        // zero Array contents
        arr.data = ptr::null();
        drop_float_array(arr);
    }

    #[test]
    fn test_coordinate_conversion() {
        let input = vec![[1.0, 2.0], [3.0, 4.0]];
        let output = "_ibE_seK_seK_seK";
        let input_arr: Array = input.as_slice().into();
        let transformed: String = super::string_from_arr(input_arr, 5);
        assert_eq!(transformed, output);
    }

    #[test]
    fn test_string_conversion() {
        let input = "_ibE_seK_seK_seK".to_string();
        let output = [[1.0, 2.0], [3.0, 4.0]];
        // String to Array
        let transformed: Array = super::arr_from_string(input, 5);
        // Array to Vec
        let transformed_arr: &[[f64; 2]] = transformed.into();
        assert_eq!(transformed_arr, output);
    }

    #[test]
    #[should_panic]
    fn test_bad_string_conversion() {
        let input = "_p~iF~ps|U_u🗑lLnnqC_mqNvxq`@".to_string();
        let output = vec![[1.0, 2.0], [3.0, 4.0]];
        // String to Array
        let transformed: Array = super::arr_from_string(input, 5);
        // Array to Vec
        let transformed_arr: &[[f64; 2]] = transformed.into();
        // this will fail, bc transformed_arr is [[NaN, NaN]]
        assert_eq!(transformed_arr, output.as_slice());
    }

    #[test]
    fn test_ffi_polyline_decoding() {
        let input = CString::new("_ibE_seK_seK_seK").unwrap().as_ptr();
        let result: &[[f64; 2]] = decode_polyline_ffi(input, 5).into();
        assert_eq!(result, [[1.0, 2.0], [3.0, 4.0]]);
        drop_float_array(result.into());
    }

    #[test]
    fn test_ffi_coordinate_encoding() {
        let input: Array = vec![[1.0, 2.0], [3.0, 4.0]].as_slice().into();
        let output = "_ibE_seK_seK_seK".to_string();
        let pl = encode_coordinates_ffi(input, 5);
        // Allocate a new String
        let result = unsafe { CStr::from_ptr(pl).to_str().unwrap() };
        assert_eq!(result, output);
        // Drop received FFI data
        drop_cstring(pl);
    }

    #[test]
    fn test_long_running() {
        let input = CString::new("_ibE_seK_seK_seK").unwrap().as_ptr();
        for _ in 0..100 {
            let result: &[[f64; 2]] = decode_polyline_ffi(input, 5).into();
            assert_eq!(result, [[1.0, 2.0], [3.0, 4.0]]);
            drop_float_array(result.into());
        }

    }
}
<|endoftext|>