<commit_before>
use std::boxed::Box;
use std::ops::Neg;
use std::sync::Arc;
use num::traits::{One, Zero};

use na::{Iso2, Mat1, Norm, Rot2, Translation, Vec1, Vec2};
use ncollide::inspection::{Repr2};
use ncollide::shape::{Compound, Cone, Cuboid, Cylinder};
use nphysics::object::{RigidBody};
use protobuf::repeated::RepeatedField;

use constants::*;
use contracts::ship as contracts;
use tagtree;

enum Part {
    Vessel { width: f64, length: f64 },
    FuelTank { radius: f64, length: f64 },
    Engine { radius: f64, length: f64, group: i32 }
}

struct PointMass {
    center: Vec2<f64>,
    mass: f64
}

type Shaped = Box<Repr2<f64>>;
type ArcShaped = Arc<Shaped>;

impl PointMass {

    fn mass_contrib (&self) -> Vec2<f64> {
        self.center * self.mass
    }

    fn moment_contrib (&self) -> f64 {
        self.mass * self.center.sqnorm()
    }

}

impl Part {

    fn contract (&self) -> contracts::Part {
        let mut part = contracts::Part::new();
        match self {
            &Part::Vessel { width, length } => {
                let mut vessel = contracts::Vessel::new();
                vessel.set_width(width);
                vessel.set_length(length);
                part.set_vessel(vessel);
            }
            &Part::FuelTank {radius, length} => {
                let mut fueltank = contracts::FuelTank::new();
                fueltank.set_radius(radius);
                fueltank.set_length(length);
                part.set_fuelTank(fueltank);
            }
            &Part::Engine {radius, length, group} => {
                let mut engine= contracts::Engine::new();
                engine.set_radius(radius);
                engine.set_length(length);
                engine.set_group(group);
                part.set_engine(engine);
            }
        }
        part
    }

    fn mass (&self) -> f64 {
        match self {
            &Part::Vessel {width, length} => {
                VESSEL_DENSITY * width * length
            }
            &Part::FuelTank {radius, length} => {
                FUELTANK_DENSITY * radius * length
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                ENGINE_DENSITY * radius * length * 0.5
            }
        }
    }

    fn geometry (&self) -> ArcShaped {
        Arc::new(match self {
            &Part::Vessel {width, length} => {
                Box::new(Cuboid::new(Vec2::new(width, length))) as Shaped
            }
            &Part::FuelTank {radius, length} => {
                Box::new(Cylinder::new(length, radius)) as Shaped
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                Box::new(Cone::new(length, radius)) as Shaped
            }
        })
    }

    fn object (&self) -> RigidBody {
        match self {
            &Part::Vessel {width, length} => {
                let geom = Cuboid::new(Vec2::new(width, length));
                RigidBody::new_dynamic(geom, VESSEL_DENSITY, 1.0, 1.0)
            }
            &Part::FuelTank {radius, length} => {
                let geom = Cylinder::new(length, radius);
                RigidBody::new_dynamic(geom, FUELTANK_DENSITY, 1.0, 1.0)
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                let geom = Cone::new(length, radius);
                RigidBody::new_dynamic(geom, ENGINE_DENSITY, 1.0, 1.0)
            }
        }
    }

    fn point_mass (&self) -> PointMass {
        PointMass { center: Vec2::new(0.0,0.0), mass: self.mass() }
    }

}

#[test]
fn simple_parts () {

    let p1 = Part::Vessel { width: 2.0, length: 4.0 };
    let _p2 = Part::FuelTank { radius: 1.0, length: 5.0};
    let _p3 = Part::Engine { radius: 1.0, length: 2.0, group: 3};

    let _m1 = p1.mass();
    let _pm1 = p1.point_mass();

}

struct PartObjectCache {
    part: Part,
    object: RigidBody,
    mass: f64
}

struct Beam {
    length: f64
}

impl Beam {

    fn contract (&self) -> contracts::Beam {
        let mut beam = contracts::Beam::new();
        beam.set_length(self.length);
        beam
    }

    fn geometry (&self) -> ArcShaped {
        let geom = Cuboid::new(Vec2::new(BEAM_WIDTH, self.length));
        Arc::new(Box::new(geom))
    }

    fn object (&self) -> RigidBody {
        let geom = Cuboid::new(Vec2::new(BEAM_WIDTH, self.length));
        RigidBody::new_dynamic(geom, BEAM_DENSITY, 1.0, 1.0)
    }

    fn mass (&self) -> f64 {
        self.length * BEAM_DENSITY
    }

    fn point_mass (&self) -> PointMass {
        let midpoint = self.length / 2.0;
        PointMass { center: Vec2::new(midpoint, 0.0), mass: self.mass() }
    }

}

#[derive(Clone)]
struct Attach {
    location: f64,
    rotation: f64
}

type Structure = tagtree::TagTree<Part,Beam,Attach>;

impl Structure {

    fn contract(&self) -> contracts::Structure {
        let mut structure = contracts::Structure::new();
        // performance!
        let mut data: Vec<contracts::StructureData> = Vec::new();
        let mut counter = 0;
        for item in self.attach_iter() {
            match item {
                StructureData::Marker => {
                    data.push(contracts::EndMarker::New())
                }
                StructureData::Node(item) => {
                    let mut node = contracts::StructureNode::new();
                    counter += 1;
                    item.context.set_link(node);
                    item.structure.set_node(node);
                    node.set_attachment(item.structure.contract_attachment());
                    data.push(node)
                }
            }
        }
        structure.set_structure(RepeatedField::from_vec(data));
        structure
    }

    fn contract_node(&self, builder: &mut contracts::StructureNode) {
        match self {
            &tagtree::TagTree::Leaf(ref part) => {
                builder.set_part(part.contract())
            }
            &tagtree::TagTree::Node(ref beam, _) => {
                builder.set_beam(beam.contract())
            }
        }
    }

    fn mass(&self) -> f64 {
        match self {
            &tagtree::TagTree::Leaf(ref part) => {
                part.mass()
            }
            &tagtree::TagTree::Node(ref beam, _) => {
                beam.mass()
            }
        }
    }

    fn geometry (&self) -> ArcShaped {
        match self {
            &tagtree::TagTree::Leaf(ref part) => {
                part.geometry()
            }
            &tagtree::TagTree::Node(ref beam, _) => {
                beam.geometry()
            }
        }
    }

    fn total_mass(&self) -> f64 {
        let mut total_mass: f64 = 0.0;
        for item in self.iso_iter() {
            total_mass += item.structure.mass();
        }
        total_mass
    }

    fn point_masses(&self) -> Vec<PointMass> {
        // This smells, could probably return an iterator?
        self.iso_iter().fold(Vec::new(), |mut acc, item| {
            acc.push(PointMass{ center: item.context.translation, mass: item.structure.mass() });
            acc
        })
    }

    fn center_of_mass(&self) -> Vec2<f64> {
        self.point_masses().iter().fold(Vec2::zero(), |acc, pm| {
            acc + pm.mass_contrib()
        })
    }

    fn total_moment(&self) -> f64 {
        let mut point_masses = self.point_masses();
        let neg_center = self.center_of_mass().neg();
        for mut pm in point_masses.iter_mut() {
            pm.center.append_translation_mut(&neg_center);
        }
        point_masses.iter().fold(0.0, |acc, pm| {
            acc + pm.moment_contrib()
        })
    }

    fn compound_shape(&self) -> ArcShaped {
        let mut acc = Vec::<(Iso2<f64>,ArcShaped)>::new();
        for item in self.iso_iter() {
            acc.push((item.context, item.structure.geometry()));
        }
        Arc::new(Box::new(Compound::new(acc)))
    }

    fn rigid_body(&self) -> RigidBody {
        let shape = self.compound_shape();
        let mass_properties = Some((self.total_mass(), self.center_of_mass().to_pnt(), Mat1::new(self.total_moment())));
        RigidBody::new(shape, mass_properties, 1.0, 1.0)
    }
}

// Opportunity to move into tagtree if Attach is a monoid
struct StructureWorkItem<'a, T> {
    context: T,
    structure: &'a Structure,
}

struct StructureIsoIter<'a> {
    work: Vec<StructureWorkItem<'a, Iso2<f64>>>,
}

enum StructureLink {
    Root, Attach(Attach)
}

impl StructureLink {

    fn contract_link(&self, builder: &mut contracts::StructureNode) {
        match self {
            StructureLink::Root => {
                builder.set_root(contracts::Root::new())
            }
            StructureLink::Attach(attach) => {
                builder.set_attach(attach)
            }
        }
    }

}

struct StructureAttachIter<'a> {
    work: Vec<StructureWorkItem<'a, StructureLink>>,
}

impl Structure {
    pub fn iso_iter(&self) -> StructureIsoIter {
        let root_work_item = StructureWorkItem {
            context: Iso2::one(),
            structure: self,
        };
        StructureIsoIter { work: vec!(root_work_item) }
    }

    // Not very DRY, not exactly sure where to abstract
    pub fn attach_iter(&self) -> StructureAttachIter {
        let root_work_item = StructureWorkItem {
            context: None,
            structure: self,
        };
        StructureAttachIter { work: vec!(root_work_item) }
    }
}

impl<'a> Iterator for StructureIsoIter<'a> {

    type Item = StructureWorkItem<'a, Iso2<f64>>;

    fn next(&mut self) -> Option<Self::Item> {

        match self.work.pop() {
            None => { None }
            Some(ref curr_work) => {
                let context = curr_work.context;

                match curr_work.structure {
                    &tagtree::TagTree::Leaf(_) => {}
                    &tagtree::TagTree::Node(_, ref attachments) => {
                        // This smells, should probably rewrite as a normal for loop
                        attachments.iter().fold((), |_, &(ref attach, ref attachment)| {
                            let trn = Vec2::new(attach.location, 0.0);
                            let rot = Rot2::new(Vec1::new(attach.rotation));
                            let iso = Iso2::new_with_rotmat(trn, rot);
                            let next_context = context * iso;
                            let next_work = StructureWorkItem {
                                context: next_context,
                            structure: &**attachment
                            };

                            self.work.push(next_work);
                        })
                    }
                }

                Some(StructureWorkItem { context: context, structure: curr_work.structure })

            }
        }

    }

}

enum StructureData<T> {
    Marker,
    Node(T)
}

impl<'a> Iterator for StructureAttachIter<'a> {

    type Item = StructureData<StructureWorkItem<'a, Option<Attach>>>;

    fn next(&mut self) -> Option<Self::Item> {

        match self.work.pop() {
            None => { None }
            Some(ref curr_work) => {
                let context = curr_work.context.clone();

                match curr_work.structure {
                    &tagtree::TagTree::Leaf(_) => {}
                    &tagtree::TagTree::Node(_, ref attachments) => {
                        // This smells, should probably rewrite as a normal for loop
                        attachments.iter().fold((), |_, &(ref attach, ref attachment)| {
                            //let trn = Vec2::new(attach.location, 0.0);
                            //let rot = Rot2::new(Vec1::new(attach.rotation));
                            //let iso = Iso2::new_with_rotmat(trn, rot);
                            //let next_context = context * iso;
                            let next_context = Some(attach.clone());
                            let next_work = StructureWorkItem {
                                context: next_context,
                            structure: &**attachment,
                            };

                            self.work.push(StructureData::Node(next_work));
                        })
                    }
                }

                self.work.push(StructureData::Marker);

                Some(StructureWorkItem { context: context, structure: curr_work.structure })

            }
        }

    }

}

fn part(attrs: Part) -> Structure {
    tagtree::TagTree::Leaf(attrs)
}

fn beam(length: f64, parts: Vec<(Attach, Box<Structure>)>) -> Structure {
    tagtree::TagTree::Node(Beam {length: length}, parts)
}

#[test]
fn simple_structures () {
    let p1 = part(Part::Vessel { width: 2.0, length: 4.0 });
    let a1 = Attach{location: 2.0, rotation: 0.0};
    let p2 = part(Part::FuelTank { radius: 1.0, length: 5.0});
    let a2 = Attach{location: 8.0, rotation: 0.0};
    let p3 = part(Part::Engine { radius: 1.0, length: 2.0, group: 3});
    let a3 = Attach{location: 10.0, rotation: 0.0};
    let b1 = beam(5.0, vec![(a1, box p1),(a2, box p2),(a3, box p3)]);
    b1.mass();
}

#[test]
fn simple_ships () {
    beam(8.0, vec![
         (Attach {location: 2.0, rotation: 0.0},
          box part(Part::Vessel {width: 2.0, length: 4.0})
         ),
         (Attach {location: 6.0, rotation: 0.0},
          box part(Part::FuelTank {radius: 1.0, length: 1.5})
         ),
         (Attach {location: 8.0, rotation: 0.0},
          box part(Part::Engine {radius: 1.5, length: 0.5, group: 1})
         )
         ]
        );
}
<commit_msg>finished ship contract serialization<commit_after>
use std::boxed::Box;
use std::ops::Neg;
use std::sync::Arc;
use num::traits::{One, Zero};

use na::{Iso2, Mat1, Norm, Rot2, Translation, Vec1, Vec2};
use ncollide::inspection::{Repr2};
use ncollide::shape::{Compound, Cone, Cuboid, Cylinder};
use nphysics::object::{RigidBody};
use protobuf::repeated::RepeatedField;

use constants::*;
use contracts::ship as contracts;
use tagtree;

enum Part {
    Vessel { width: f64, length: f64 },
    FuelTank { radius: f64, length: f64 },
    Engine { radius: f64, length: f64, group: i32 }
}

struct PointMass {
    center: Vec2<f64>,
    mass: f64
}

type Shaped = Box<Repr2<f64>>;
type ArcShaped = Arc<Shaped>;

impl PointMass {

    fn mass_contrib (&self) -> Vec2<f64> {
        self.center * self.mass
    }

    fn moment_contrib (&self) -> f64 {
        self.mass * self.center.sqnorm()
    }

}

impl Part {

    fn contract (&self) -> contracts::Part {
        let mut part = contracts::Part::new();
        match self {
            &Part::Vessel { width, length } => {
                let mut vessel = contracts::Vessel::new();
                vessel.set_width(width);
                vessel.set_length(length);
                part.set_vessel(vessel);
            }
            &Part::FuelTank {radius, length} => {
                let mut fueltank = contracts::FuelTank::new();
                fueltank.set_radius(radius);
                fueltank.set_length(length);
                part.set_fuelTank(fueltank);
            }
            &Part::Engine {radius, length, group} => {
                let mut engine= contracts::Engine::new();
                engine.set_radius(radius);
                engine.set_length(length);
                engine.set_group(group);
                part.set_engine(engine);
            }
        }
        part
    }

    fn mass (&self) -> f64 {
        match self {
            &Part::Vessel {width, length} => {
                VESSEL_DENSITY * width * length
            }
            &Part::FuelTank {radius, length} => {
                FUELTANK_DENSITY * radius * length
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                ENGINE_DENSITY * radius * length * 0.5
            }
        }
    }

    fn geometry (&self) -> ArcShaped {
        Arc::new(match self {
            &Part::Vessel {width, length} => {
                Box::new(Cuboid::new(Vec2::new(width, length))) as Shaped
            }
            &Part::FuelTank {radius, length} => {
                Box::new(Cylinder::new(length, radius)) as Shaped
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                Box::new(Cone::new(length, radius)) as Shaped
            }
        })
    }

    fn object (&self) -> RigidBody {
        match self {
            &Part::Vessel {width, length} => {
                let geom = Cuboid::new(Vec2::new(width, length));
                RigidBody::new_dynamic(geom, VESSEL_DENSITY, 1.0, 1.0)
            }
            &Part::FuelTank {radius, length} => {
                let geom = Cylinder::new(length, radius);
                RigidBody::new_dynamic(geom, FUELTANK_DENSITY, 1.0, 1.0)
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                let geom = Cone::new(length, radius);
                RigidBody::new_dynamic(geom, ENGINE_DENSITY, 1.0, 1.0)
            }
        }
    }

    fn point_mass (&self) -> PointMass {
        PointMass { center: Vec2::new(0.0,0.0), mass: self.mass() }
    }

}

#[test]
fn simple_parts () {

    let p1 = Part::Vessel { width: 2.0, length: 4.0 };
    let _p2 = Part::FuelTank { radius: 1.0, length: 5.0};
    let _p3 = Part::Engine { radius: 1.0, length: 2.0, group: 3};

    let _m1 = p1.mass();
    let _pm1 = p1.point_mass();

}

struct PartObjectCache {
    part: Part,
    object: RigidBody,
    mass: f64
}

struct Beam {
    length: f64
}

impl Beam {

    fn contract (&self) -> contracts::Beam {
        let mut beam = contracts::Beam::new();
        beam.set_length(self.length);
        beam
    }

    fn geometry (&self) -> ArcShaped {
        let geom = Cuboid::new(Vec2::new(BEAM_WIDTH, self.length));
        Arc::new(Box::new(geom))
    }

    fn object (&self) -> RigidBody {
        let geom = Cuboid::new(Vec2::new(BEAM_WIDTH, self.length));
        RigidBody::new_dynamic(geom, BEAM_DENSITY, 1.0, 1.0)
    }

    fn mass (&self) -> f64 {
        self.length * BEAM_DENSITY
    }

    fn point_mass (&self) -> PointMass {
        let midpoint = self.length / 2.0;
        PointMass { center: Vec2::new(midpoint, 0.0), mass: self.mass() }
    }

}

#[derive(Clone)]
struct Attach {
    location: f64,
    rotation: f64
}

impl Attach {

    fn contract(&self) -> contracts::Attach {
        let mut attach = contracts::Attach::new();
        attach.set_location(self.location);
        attach.set_rotation(self.rotation);
        attach
    }

}

type Structure = tagtree::TagTree<Part,Beam,Attach>;

impl Structure {

    fn contract(&self) -> contracts::Structure {
        let mut structure = contracts::Structure::new();
        let datas: RepeatedField<contracts::StructureData> = self.contract_iter().collect();
        structure.set_attachments(datas);
        structure
    }

    fn set_contract_node_for(&self, builder: &mut contracts::StructureNode) {
        match self {
            &tagtree::TagTree::Leaf(ref part) => {
                builder.set_part(part.contract())
            }
            &tagtree::TagTree::Node(ref beam, _) => {
                builder.set_beam(beam.contract())
            }
        }
    }

    fn mass(&self) -> f64 {
        match self {
            &tagtree::TagTree::Leaf(ref part) => {
                part.mass()
            }
            &tagtree::TagTree::Node(ref beam, _) => {
                beam.mass()
            }
        }
    }

    fn geometry (&self) -> ArcShaped {
        match self {
            &tagtree::TagTree::Leaf(ref part) => {
                part.geometry()
            }
            &tagtree::TagTree::Node(ref beam, _) => {
                beam.geometry()
            }
        }
    }

    fn total_mass(&self) -> f64 {
        let mut total_mass: f64 = 0.0;
        for item in self.iso_iter() {
            total_mass += item.structure.mass();
        }
        total_mass
    }

    fn point_masses(&self) -> Vec<PointMass> {
        // This smells, could probably return an iterator?
        self.iso_iter().fold(Vec::new(), |mut acc, item| {
            acc.push(PointMass{ center: item.context.translation, mass: item.structure.mass() });
            acc
        })
    }

    fn center_of_mass(&self) -> Vec2<f64> {
        self.point_masses().iter().fold(Vec2::zero(), |acc, pm| {
            acc + pm.mass_contrib()
        })
    }

    fn total_moment(&self) -> f64 {
        let mut point_masses = self.point_masses();
        let neg_center = self.center_of_mass().neg();
        for mut pm in point_masses.iter_mut() {
            pm.center.append_translation_mut(&neg_center);
        }
        point_masses.iter().fold(0.0, |acc, pm| {
            acc + pm.moment_contrib()
        })
    }

    fn compound_shape(&self) -> ArcShaped {
        let mut acc = Vec::<(Iso2<f64>,ArcShaped)>::new();
        for item in self.iso_iter() {
            acc.push((item.context, item.structure.geometry()));
        }
        Arc::new(Box::new(Compound::new(acc)))
    }

    fn rigid_body(&self) -> RigidBody {
        let shape = self.compound_shape();
        let mass_properties = Some((self.total_mass(), self.center_of_mass().to_pnt(), Mat1::new(self.total_moment())));
        RigidBody::new(shape, mass_properties, 1.0, 1.0)
    }
}

// Opportunity to move into tagtree if Attach is a monoid
struct StructureWorkItem<'a, T> {
    context: T,
    structure: &'a Structure,
}

struct StructureIsoIter<'a> {
    work: Vec<StructureWorkItem<'a, Iso2<f64>>>,
}

enum StructureLink {
    Root, Attach(Attach)
}

impl StructureLink {

    fn set_link_for(&self, builder: &mut contracts::StructureNode) {
        match self {
            &StructureLink::Root => {
                builder.set_root(contracts::Root::new())
            }
            &StructureLink::Attach(ref attach) => {
                builder.set_attach(attach.contract())
            }
        }
    }

}

struct StructureContractIter<'a> {
    work: Vec<Option<StructureWorkItem<'a, Option<Attach>>>>,
}

impl Structure {
    pub fn iso_iter(&self) -> StructureIsoIter {
        let root_work_item = StructureWorkItem {
            context: Iso2::one(),
            structure: self,
        };
        StructureIsoIter { work: vec!(root_work_item) }
    }

    // Not very DRY, not exactly sure where to abstract
    pub fn contract_iter(&self) -> StructureContractIter {
        let root_work_item = StructureWorkItem {
            context: None,
            structure: self,
        };
        StructureContractIter { work: vec!(Some(root_work_item)) }
    }
}

impl<'a> Iterator for StructureIsoIter<'a> {

    type Item = StructureWorkItem<'a, Iso2<f64>>;

    fn next(&mut self) -> Option<Self::Item> {

        match self.work.pop() {
            None => { None }
            Some(ref curr_work) => {
                let context = curr_work.context;

                match curr_work.structure {
                    &tagtree::TagTree::Leaf(_) => {}
                    &tagtree::TagTree::Node(_, ref attachments) => {
                        // This smells, should probably rewrite as a normal for loop
                        attachments.iter().fold((), |_, &(ref attach, ref attachment)| {
                            let trn = Vec2::new(attach.location, 0.0);
                            let rot = Rot2::new(Vec1::new(attach.rotation));
                            let iso = Iso2::new_with_rotmat(trn, rot);
                            let next_context = context * iso;
                            let next_work = StructureWorkItem {
                                context: next_context,
                            structure: &**attachment
                            };

                            self.work.push(next_work);
                        })
                    }
                }

                Some(StructureWorkItem { context: context, structure: curr_work.structure })

            }
        }

    }

}

enum StructureData<T> {
    Marker,
    Node(T)
}

impl<'a> Iterator for StructureContractIter<'a> {

    type Item = contracts::StructureData;

    fn next(&mut self) -> Option<Self::Item> {

        match self.work.pop() {
            None => { None }
            Some(None) => {
                let mut marker_data = contracts::StructureData::new();
                marker_data.set_marker(contracts::EndMarker::new());
                Some(marker_data)
            }
            Some(Some(ref curr_work)) => {
                // After a leaf or all of a beam's children, so push on the stack first
                self.work.push(None);

                match curr_work.structure {
                    &tagtree::TagTree::Leaf(_) => {}
                    &tagtree::TagTree::Node(_, ref attachments) => {
                        // This smells, should probably rewrite as a normal for loop
                        attachments.iter().fold((), |_, &(ref attach, ref attachment)| {
                            //let trn = Vec2::new(attach.location, 0.0);
                            //let rot = Rot2::new(Vec1::new(attach.rotation));
                            //let iso = Iso2::new_with_rotmat(trn, rot);
                            //let next_context = context * iso;
                            let next_context = Some(attach.clone());
                            let next_work = StructureWorkItem {
                                context: next_context,
                            structure: &**attachment,
                            };

                            self.work.push(Some(next_work));
                        })
                    }
                }

                let mut data = contracts::StructureData::new();
                let mut node = contracts::StructureNode::new();
                curr_work.structure.set_contract_node_for(&mut node);
                match curr_work.context {
                    None => { node.set_root(contracts::Root::new()) }
                    Some(ref attach) => { node.set_attach(attach.contract()) }
                }
                data.set_node(node);
                Some(data)

            }
        }

    }

}

fn part(attrs: Part) -> Structure {
    tagtree::TagTree::Leaf(attrs)
}

fn beam(length: f64, parts: Vec<(Attach, Box<Structure>)>) -> Structure {
    tagtree::TagTree::Node(Beam {length: length}, parts)
}

#[test]
fn simple_structures () {
    let p1 = part(Part::Vessel { width: 2.0, length: 4.0 });
    let a1 = Attach{location: 2.0, rotation: 0.0};
    let p2 = part(Part::FuelTank { radius: 1.0, length: 5.0});
    let a2 = Attach{location: 8.0, rotation: 0.0};
    let p3 = part(Part::Engine { radius: 1.0, length: 2.0, group: 3});
    let a3 = Attach{location: 10.0, rotation: 0.0};
    let b1 = beam(5.0, vec![(a1, box p1),(a2, box p2),(a3, box p3)]);
    b1.mass();
}

#[test]
fn simple_ships () {
    beam(8.0, vec![
         (Attach {location: 2.0, rotation: 0.0},
          box part(Part::Vessel {width: 2.0, length: 4.0})
         ),
         (Attach {location: 6.0, rotation: 0.0},
          box part(Part::FuelTank {radius: 1.0, length: 1.5})
         ),
         (Attach {location: 8.0, rotation: 0.0},
          box part(Part::Engine {radius: 1.5, length: 0.5, group: 1})
         )
         ]
        );
}
<|endoftext|>


<commit_before>#![deny(warnings)]
extern crate extra;
use extra::option::OptionalExt;
use extra::io::{fail, WriteExt};

use std::env::args;
use std::io::{self, Write};

#[derive(Debug, Clone)]
pub enum Token {
    Plus,
    Minus,
    Divide,
    Multiply,
    Exponent,
    OpenParen,
    CloseParen,
    Number(String),
}

impl Token {
    pub fn to_str(&self) -> &'static str {
        match self {
            &Token::Plus       => "Plus",
            &Token::Minus      => "Minus",
            &Token::Divide     => "Divide",
            &Token::Multiply   => "Multiply",
            &Token::Exponent   => "Exponent",
            &Token::OpenParen  => "OpenParen",
            &Token::CloseParen => "CloseParen",
            &Token::Number(_)  => "Number",
        }
    }

    pub fn to_string(&self) -> String {
        self.to_str().to_owned()
    }
}

#[derive(Debug,  Clone)]
pub enum ParseError {
    InvalidNumber(String),
    UnrecognizedToken(String),
    UnexpectedToken(String, &'static str),
    UnexpectedEndOfInput,
    OtherError(String),
}

#[derive(Clone,Debug)]
pub struct IntermediateResult {
    value: f64,
    tokens_read: usize,
}

impl IntermediateResult {
    fn new(value: f64, tokens_read: usize) -> Self {
        IntermediateResult {
            value: value,
            tokens_read: tokens_read,
        }
    }
}

pub trait OperatorFunctions {
    fn is_operator(self) -> bool;
    fn operator_type(self) -> Token;
}

impl OperatorFunctions for char {
    fn is_operator(self) -> bool {
        self == '+' ||
        self == '-' ||
        self == '*' ||
        self == '/' ||
        self == '^' ||
        self == '(' ||
        self == ')'
    }

    fn operator_type(self) -> Token {
        match self {
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Divide,
            '*' => Token::Multiply,
            '^' => Token::Exponent,
            '(' => Token::OpenParen,
            ')' => Token::CloseParen,
            _   => fail("Invalid operator", &mut io::stderr())
        }
    }
}

pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    // CONSIDER: input.len() too generous?
    let mut tokens = Vec::with_capacity(input.len());

    // TODO: Not this. Modify to use iterator
    let chars: Vec<char> = input.chars().collect();

    let input_length = chars.len();
    let mut current_pos = 0;
    while current_pos < input_length {
        let c = chars[current_pos];
        if c.is_digit(10) {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::Number(token_string));
        } else if c.is_operator() {
            tokens.push(c.operator_type());
            current_pos += 1;
        } else if c.is_whitespace() {
            current_pos += 1;
        } else {
            let token_string = consume_until_new_token(&chars[current_pos..]);
            return Err(ParseError::UnrecognizedToken(token_string));
        }
    }
    Ok(tokens)
}

fn consume_number(input: &[char]) -> String {
    // CONSIDER: input.len seems a bit generous
    let mut number = String::with_capacity(input.len());
    let mut has_decimal_point = false;
    for &c in input {
        if c == '.' {
            if has_decimal_point {
                break;
            } else {
                number.push(c);
                has_decimal_point = true;
            }
        } else if c.is_digit(10) {
            number.push(c);
        } else {
            break;
        }
    }
    number
}

fn consume_until_new_token(input: &[char]) -> String {
    input.iter()
         .take_while(|c| !(c.is_whitespace() || c.is_operator() || c.is_digit(10)))
         .map(|&c| c)
         .collect()
}

// Addition and subtraction
pub fn e_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut t1 = try!(t_expr(token_list));
    let mut index = t1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Plus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value += t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Minus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value -= t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        };
        index = t1.tokens_read;
    }
    Ok(t1)
}

// Multiplication and division
pub fn t_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut f1 = try!(f_expr(token_list));
    let mut index = f1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Multiply => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            Token::Divide => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                if f2.value == 0.0 {
                    return Err(ParseError::OtherError("Divide by zero error".to_owned()));
                } else {
                    f1.value /= f2.value;
                    f1.tokens_read += f2.tokens_read + 1;
                }
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = try!(g_expr(token_list));
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    Ok(g1)
}

// Numbers and parenthesized expressions
pub fn g_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    if !token_list.is_empty() {
        match token_list[0] {
            Token::Number(ref n) => {
                n.parse::<f64>()
                 .map_err(|_| ParseError::InvalidNumber(n.clone()))
                 .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            Token::Minus => {
                if token_list.len() > 1 {
                    if let Token::Number(ref n) = token_list[1] {
                        n.parse::<f64>()
                         .map_err(|_| ParseError::InvalidNumber(n.clone()))
                         .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                    } else {
                        Err(ParseError::UnexpectedToken(token_list[1].to_string(), "number"))
                    }
                } else {
                    Err(ParseError::UnexpectedEndOfInput)
                }
            }
            Token::OpenParen => {
                let expr = e_expr(&token_list[1..]);
                match expr {
                    Ok(ir) => {
                        let close_paren = ir.tokens_read + 1;
                        if close_paren < token_list.len() {
                            match token_list[close_paren] {
                                Token::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].to_string(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].to_string(), "number"))
        }
    } else {
        Err(ParseError::UnexpectedEndOfInput)
    }
}

pub fn parse(tokens: Vec<Token>) -> Result<String, ParseError> {
    e_expr(&tokens).map(|answer| answer.value.to_string())
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn simple_addition() {
        assert_eq!(tokenize("12+3").and_then(parse).unwrap(), "15");
    }

    #[test]
    fn addition() {
        assert_eq!(tokenize("12+3+5").and_then(parse).unwrap(), "20");
    }

    #[test]
    fn simple_subtraction() {
        assert_eq!(tokenize("12-3").and_then(parse).unwrap(), "9");
    }

    #[test]
    fn subtraction() {
        assert_eq!(tokenize("12-3-4").and_then(parse).unwrap(), "5");
    }

    #[test]
    fn mixed_addition_and_subtraction() {
        assert_eq!(tokenize("12+3-4+8-2-3").and_then(parse).unwrap(), "14");
    }

    #[test]
    fn simple_parentheses() {
        assert_eq!(tokenize("((3))").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("(12+(2+3))").and_then(parse).unwrap(), "17");
        assert_eq!(tokenize("12+(2+3)").and_then(parse).unwrap(), "17");
    }

    #[test]
    fn parentheses() {
        assert_eq!(tokenize("12+(2+(3+5))+4+(((6)))").and_then(parse).unwrap(), "32");
    }

    #[test]
    fn multiplication() {
        assert_eq!(tokenize("3*3").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("3*5").and_then(parse).unwrap(), "15");
        assert_eq!(tokenize("0*5").and_then(parse).unwrap(), "0");
        assert_eq!(tokenize("5*4*3*2*1").and_then(parse).unwrap(), "120");
        assert_eq!(tokenize("(5*4)*3*(2*1)").and_then(parse).unwrap(), "120");
    }

    #[test]
    fn division() {
        assert_eq!(tokenize("12/4").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("12/3").and_then(parse).unwrap(), "4");
        assert_eq!(tokenize("5/2").and_then(parse).unwrap(), "2.5");
        assert_eq!(tokenize("120/5/4/3/2").and_then(parse).unwrap(), "1");
        assert_eq!(tokenize("(120/5)/4/(3/2)").and_then(parse).unwrap(), "4");
    }

    #[test]
    fn exponentiation() {
        assert_eq!(tokenize("3^2").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("2^3^2").and_then(parse).unwrap(), "512");
        assert_eq!(tokenize("2^(2+1)^2").and_then(parse).unwrap(), "512");
    }
}

fn eval(input: &str) -> String {
    match tokenize(input).and_then(parse) {
        Ok(s) => s,
        Err(e) => match e {
            ParseError::InvalidNumber(s) => ["Error: Invalid number: ", s.as_str() ].concat(),
            ParseError::UnrecognizedToken(s) => ["Error: Unrecognized token: ", s.as_str()].concat(),
            ParseError::UnexpectedToken(found, expected) => ["Error: Unexpected token: expected [", expected, "] but found '", found.as_str(), "'"].concat(),
            ParseError::UnexpectedEndOfInput => "Error: Unexpected end of input.".to_owned(),
            ParseError::OtherError(s) => s,
        }
    }
}

fn main() {
    let args = args();
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    if args.len() > 1 {
        let input: Vec<String> = args.skip(1).collect();
        stdout.writeln(eval(&input.join("")).as_bytes()).try(&mut stderr);
    } else {
        let prompt = "[]> ".as_bytes();
        loop {
            stdout.write(prompt).try(&mut stderr);
            stdout.flush().try(&mut stderr);
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                       .try(&mut stderr);
            match input.trim() {
                "exit" => break,
                s => {
                    stdout.writeln(eval(s).as_bytes()).try(&mut stderr);
                    stdout.flush().try(&mut stderr);
                },
            }
        }
    }
}
<commit_msg>Exit on EOF, don't error on empty line<commit_after>#![deny(warnings)]
extern crate extra;
use extra::option::OptionalExt;
use extra::io::{fail, WriteExt};

use std::env::args;
use std::io::{self, Write};

#[derive(Debug, Clone)]
pub enum Token {
    Plus,
    Minus,
    Divide,
    Multiply,
    Exponent,
    OpenParen,
    CloseParen,
    Number(String),
}

impl Token {
    pub fn to_str(&self) -> &'static str {
        match self {
            &Token::Plus       => "Plus",
            &Token::Minus      => "Minus",
            &Token::Divide     => "Divide",
            &Token::Multiply   => "Multiply",
            &Token::Exponent   => "Exponent",
            &Token::OpenParen  => "OpenParen",
            &Token::CloseParen => "CloseParen",
            &Token::Number(_)  => "Number",
        }
    }

    pub fn to_string(&self) -> String {
        self.to_str().to_owned()
    }
}

#[derive(Debug,  Clone)]
pub enum ParseError {
    InvalidNumber(String),
    UnrecognizedToken(String),
    UnexpectedToken(String, &'static str),
    UnexpectedEndOfInput,
    OtherError(String),
}

#[derive(Clone,Debug)]
pub struct IntermediateResult {
    value: f64,
    tokens_read: usize,
}

impl IntermediateResult {
    fn new(value: f64, tokens_read: usize) -> Self {
        IntermediateResult {
            value: value,
            tokens_read: tokens_read,
        }
    }
}

pub trait OperatorFunctions {
    fn is_operator(self) -> bool;
    fn operator_type(self) -> Token;
}

impl OperatorFunctions for char {
    fn is_operator(self) -> bool {
        self == '+' ||
        self == '-' ||
        self == '*' ||
        self == '/' ||
        self == '^' ||
        self == '(' ||
        self == ')'
    }

    fn operator_type(self) -> Token {
        match self {
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Divide,
            '*' => Token::Multiply,
            '^' => Token::Exponent,
            '(' => Token::OpenParen,
            ')' => Token::CloseParen,
            _   => fail("Invalid operator", &mut io::stderr())
        }
    }
}

pub fn tokenize(input: &str) -> Result<Vec<Token>, ParseError> {
    // CONSIDER: input.len() too generous?
    let mut tokens = Vec::with_capacity(input.len());

    // TODO: Not this. Modify to use iterator
    let chars: Vec<char> = input.chars().collect();

    let input_length = chars.len();
    let mut current_pos = 0;
    while current_pos < input_length {
        let c = chars[current_pos];
        if c.is_digit(10) {
            let token_string = consume_number(&chars[current_pos..]);
            current_pos += token_string.len();
            tokens.push(Token::Number(token_string));
        } else if c.is_operator() {
            tokens.push(c.operator_type());
            current_pos += 1;
        } else if c.is_whitespace() {
            current_pos += 1;
        } else {
            let token_string = consume_until_new_token(&chars[current_pos..]);
            return Err(ParseError::UnrecognizedToken(token_string));
        }
    }
    Ok(tokens)
}

fn consume_number(input: &[char]) -> String {
    // CONSIDER: input.len seems a bit generous
    let mut number = String::with_capacity(input.len());
    let mut has_decimal_point = false;
    for &c in input {
        if c == '.' {
            if has_decimal_point {
                break;
            } else {
                number.push(c);
                has_decimal_point = true;
            }
        } else if c.is_digit(10) {
            number.push(c);
        } else {
            break;
        }
    }
    number
}

fn consume_until_new_token(input: &[char]) -> String {
    input.iter()
         .take_while(|c| !(c.is_whitespace() || c.is_operator() || c.is_digit(10)))
         .map(|&c| c)
         .collect()
}

// Addition and subtraction
pub fn e_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut t1 = try!(t_expr(token_list));
    let mut index = t1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Plus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value += t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Minus => {
                let t2 = try!(t_expr(&token_list[index+1..]));
                t1.value -= t2.value;
                t1.tokens_read += t2.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        };
        index = t1.tokens_read;
    }
    Ok(t1)
}

// Multiplication and division
pub fn t_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut f1 = try!(f_expr(token_list));
    let mut index = f1.tokens_read;

    while index < token_list.len() {
        match token_list[index] {
            Token::Multiply => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                f1.value *= f2.value;
                f1.tokens_read += f2.tokens_read + 1;
            }
            Token::Divide => {
                let f2 = try!(f_expr(&token_list[index+1..]));
                if f2.value == 0.0 {
                    return Err(ParseError::OtherError("Divide by zero error".to_owned()));
                } else {
                    f1.value /= f2.value;
                    f1.tokens_read += f2.tokens_read + 1;
                }
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = f1.tokens_read;
    }
    Ok(f1)
}

// Exponentiation
pub fn f_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    let mut g1 = try!(g_expr(token_list));
    let mut index = g1.tokens_read;
    let token_len = token_list.len();
    while index < token_len {
        match token_list[index] {
            Token::Exponent => {
                let f = try!(f_expr(&token_list[index+1..]));
                g1.value = g1.value.powf(f.value);
                g1.tokens_read += f.tokens_read + 1;
            }
            Token::Number(ref n) => return Err(ParseError::UnexpectedToken(n.clone(),"operator")),
            _ => break,
        }
        index = g1.tokens_read;
    }
    Ok(g1)
}

// Numbers and parenthesized expressions
pub fn g_expr(token_list: &[Token]) -> Result<IntermediateResult, ParseError> {
    if !token_list.is_empty() {
        match token_list[0] {
            Token::Number(ref n) => {
                n.parse::<f64>()
                 .map_err(|_| ParseError::InvalidNumber(n.clone()))
                 .and_then(|num| Ok(IntermediateResult::new(num, 1)))
            }
            Token::Minus => {
                if token_list.len() > 1 {
                    if let Token::Number(ref n) = token_list[1] {
                        n.parse::<f64>()
                         .map_err(|_| ParseError::InvalidNumber(n.clone()))
                         .and_then(|num| Ok(IntermediateResult::new(-1.0 * num, 2)))
                    } else {
                        Err(ParseError::UnexpectedToken(token_list[1].to_string(), "number"))
                    }
                } else {
                    Err(ParseError::UnexpectedEndOfInput)
                }
            }
            Token::OpenParen => {
                let expr = e_expr(&token_list[1..]);
                match expr {
                    Ok(ir) => {
                        let close_paren = ir.tokens_read + 1;
                        if close_paren < token_list.len() {
                            match token_list[close_paren] {
                                Token::CloseParen => Ok(IntermediateResult::new(ir.value, close_paren+1)),
                                _ => Err(ParseError::UnexpectedToken(token_list[close_paren].to_string(), ")")),
                            }
                        } else {
                            Err(ParseError::OtherError("no matching close parenthesis found.".to_owned()))
                        }
                    }
                    Err(e) => Err(e),
                }
            }
            _ => Err(ParseError::UnexpectedToken(token_list[0].to_string(), "number"))
        }
    } else {
        Err(ParseError::UnexpectedEndOfInput)
    }
}

pub fn parse(tokens: Vec<Token>) -> Result<String, ParseError> {
    e_expr(&tokens).map(|answer| answer.value.to_string())
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn simple_addition() {
        assert_eq!(tokenize("12+3").and_then(parse).unwrap(), "15");
    }

    #[test]
    fn addition() {
        assert_eq!(tokenize("12+3+5").and_then(parse).unwrap(), "20");
    }

    #[test]
    fn simple_subtraction() {
        assert_eq!(tokenize("12-3").and_then(parse).unwrap(), "9");
    }

    #[test]
    fn subtraction() {
        assert_eq!(tokenize("12-3-4").and_then(parse).unwrap(), "5");
    }

    #[test]
    fn mixed_addition_and_subtraction() {
        assert_eq!(tokenize("12+3-4+8-2-3").and_then(parse).unwrap(), "14");
    }

    #[test]
    fn simple_parentheses() {
        assert_eq!(tokenize("((3))").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("(12+(2+3))").and_then(parse).unwrap(), "17");
        assert_eq!(tokenize("12+(2+3)").and_then(parse).unwrap(), "17");
    }

    #[test]
    fn parentheses() {
        assert_eq!(tokenize("12+(2+(3+5))+4+(((6)))").and_then(parse).unwrap(), "32");
    }

    #[test]
    fn multiplication() {
        assert_eq!(tokenize("3*3").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("3*5").and_then(parse).unwrap(), "15");
        assert_eq!(tokenize("0*5").and_then(parse).unwrap(), "0");
        assert_eq!(tokenize("5*4*3*2*1").and_then(parse).unwrap(), "120");
        assert_eq!(tokenize("(5*4)*3*(2*1)").and_then(parse).unwrap(), "120");
    }

    #[test]
    fn division() {
        assert_eq!(tokenize("12/4").and_then(parse).unwrap(), "3");
        assert_eq!(tokenize("12/3").and_then(parse).unwrap(), "4");
        assert_eq!(tokenize("5/2").and_then(parse).unwrap(), "2.5");
        assert_eq!(tokenize("120/5/4/3/2").and_then(parse).unwrap(), "1");
        assert_eq!(tokenize("(120/5)/4/(3/2)").and_then(parse).unwrap(), "4");
    }

    #[test]
    fn exponentiation() {
        assert_eq!(tokenize("3^2").and_then(parse).unwrap(), "9");
        assert_eq!(tokenize("2^3^2").and_then(parse).unwrap(), "512");
        assert_eq!(tokenize("2^(2+1)^2").and_then(parse).unwrap(), "512");
    }
}

fn eval(input: &str) -> String {
    match tokenize(input).and_then(parse) {
        Ok(s) => s,
        Err(e) => match e {
            ParseError::InvalidNumber(s) => ["Error: Invalid number: ", s.as_str() ].concat(),
            ParseError::UnrecognizedToken(s) => ["Error: Unrecognized token: ", s.as_str()].concat(),
            ParseError::UnexpectedToken(found, expected) => ["Error: Unexpected token: expected [", expected, "] but found '", found.as_str(), "'"].concat(),
            ParseError::UnexpectedEndOfInput => "Error: Unexpected end of input.".to_owned(),
            ParseError::OtherError(s) => s,
        }
    }
}

fn main() {
    let args = args();
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    if args.len() > 1 {
        let input: Vec<String> = args.skip(1).collect();
        stdout.writeln(eval(&input.join("")).as_bytes()).try(&mut stderr);
    } else {
        let prompt = "[]> ".as_bytes();
        loop {
            stdout.write(prompt).try(&mut stderr);
            stdout.flush().try(&mut stderr);
            let mut input = String::new();
            io::stdin().read_line(&mut input)
                       .try(&mut stderr);
            if input.is_empty() {
                break;
            } else {
                match input.trim() {
                    "" => (),
                    "exit" => break,
                    s => {
                        stdout.writeln(eval(s).as_bytes()).try(&mut stderr);
                        stdout.flush().try(&mut stderr);
                    },
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
!poll #announcements Poll text goes here!
:one: Option one
:two: Option two

From @Bot in #announcements
Poll from @jkcclemens:
Poll text goes here!
:one: – Option one
:two: – Option two

@Bot reacts to the message with all the options

!poll #general Some other poll
Auto-generate options
No custom emoji

!poll #channel Another custom poll
:thumbsup: Yes
:thumbsdown: No
*/

use LalafellBot;
use commands::*;

use discord::model::{ServerId, UserId, ReactionEmoji, Channel};
use discord::builders::EmbedBuilder;

use xivdb::error::*;

use std::sync::Arc;

const USAGE: &'static str = "!poll <channel> <poll text>\n<option>\n<option>...";

pub struct PollCommand {
  bot: Arc<LalafellBot>
}

impl PollCommand {
  pub fn new(bot: Arc<LalafellBot>) -> PollCommand {
    PollCommand {
      bot: bot
    }
  }
}

impl PollCommand {
  fn nick_or_name(&self, server: ServerId, user: UserId) -> Option<String> {
    match self.bot.discord.get_member(server, user) {
      Ok(m) => Some(m.nick.unwrap_or(m.user.name)),
      Err(_) => None
    }
  }
}

impl<'a> Command<'a> for PollCommand {
  fn run(&self, msg: &Message, _: &[&str]) -> CommandResult<'a> {
    let lines: Vec<&str> = msg.content.split('\n').collect();
    let params: Vec<&str> = lines[0].split_whitespace().skip(1).collect();
    let options = &lines[1..];
    if params.is_empty() || options.len() < 2 {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough parameters.")
          .description(USAGE))
        .wrap());
    }
    if options.len() > 9 {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .description("No more than nine poll options can be specified."))
        .wrap());
    }
    let message = params.join(" ");
    let channel = match self.bot.discord.get_channel(msg.channel_id) {
      Ok(Channel::Public(c)) => c,
      _ => return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .description("This command must be used in a public channel."))
        .wrap())
    };
    self.bot.discord.delete_message(msg.channel_id, msg.id).chain_err(|| "could not delete original message")?;
    let name = self.nick_or_name(channel.server_id, msg.author.id).unwrap_or_else(|| "someone".into());
    let poll = Poll::new(name, &message, options);
    let embed = self.bot.discord.send_embed(channel.id, "", poll.create_embed()).chain_err(|| "could not send embed")?;
    for i in 0..poll.options.len() {
      self.bot.discord.add_reaction(embed.channel_id, embed.id, ReactionEmoji::Unicode(format!("{}⃣", i + 1))).chain_err(|| "could not add reaction")?;
    }
    Ok(CommandSuccess::default())
  }
}

struct Poll {
  author: String,
  text: String,
  options: Vec<String>
}

impl Poll {
  fn new(author: String, text: &str, options: &[&str]) -> Poll {
    Poll {
      author: author,
      text: text.to_string(),
      options: options.iter().map(|x| x.to_string()).collect()
    }
  }

  fn create_embed(&self) -> Box<FnBox(EmbedBuilder) -> EmbedBuilder> {
    let name = self.author.clone();
    let options = self.options.iter()
      .enumerate()
      .map(|(i, x)| format!("{}⃣ – {}", i + 1, x))
      .collect::<Vec<_>>()
      .join("\n");
    let desc = format!("{}\n{}", self.text, options);
    box move |e: EmbedBuilder| {
      e
        .title(&format!("Poll by {}", name))
        .description(&desc)
    }
  }
}
<commit_msg>fix: correct usage<commit_after>use LalafellBot;
use commands::*;

use discord::model::{ServerId, UserId, ReactionEmoji, Channel};
use discord::builders::EmbedBuilder;

use xivdb::error::*;

use std::sync::Arc;

const USAGE: &'static str = "!poll <poll text>\n<option>\n<option>...";

pub struct PollCommand {
  bot: Arc<LalafellBot>
}

impl PollCommand {
  pub fn new(bot: Arc<LalafellBot>) -> PollCommand {
    PollCommand {
      bot: bot
    }
  }
}

impl PollCommand {
  fn nick_or_name(&self, server: ServerId, user: UserId) -> Option<String> {
    match self.bot.discord.get_member(server, user) {
      Ok(m) => Some(m.nick.unwrap_or(m.user.name)),
      Err(_) => None
    }
  }
}

impl<'a> Command<'a> for PollCommand {
  fn run(&self, msg: &Message, _: &[&str]) -> CommandResult<'a> {
    let lines: Vec<&str> = msg.content.split('\n').collect();
    let params: Vec<&str> = lines[0].split_whitespace().skip(1).collect();
    let options = &lines[1..];
    if params.is_empty() || options.len() < 2 {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough parameters.")
          .description(USAGE))
        .wrap());
    }
    if options.len() > 9 {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .description("No more than nine poll options can be specified."))
        .wrap());
    }
    let message = params.join(" ");
    let channel = match self.bot.discord.get_channel(msg.channel_id) {
      Ok(Channel::Public(c)) => c,
      _ => return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .description("This command must be used in a public channel."))
        .wrap())
    };
    self.bot.discord.delete_message(msg.channel_id, msg.id).chain_err(|| "could not delete original message")?;
    let name = self.nick_or_name(channel.server_id, msg.author.id).unwrap_or_else(|| "someone".into());
    let poll = Poll::new(name, &message, options);
    let embed = self.bot.discord.send_embed(channel.id, "", poll.create_embed()).chain_err(|| "could not send embed")?;
    for i in 0..poll.options.len() {
      self.bot.discord.add_reaction(embed.channel_id, embed.id, ReactionEmoji::Unicode(format!("{}⃣", i + 1))).chain_err(|| "could not add reaction")?;
    }
    Ok(CommandSuccess::default())
  }
}

struct Poll {
  author: String,
  text: String,
  options: Vec<String>
}

impl Poll {
  fn new(author: String, text: &str, options: &[&str]) -> Poll {
    Poll {
      author: author,
      text: text.to_string(),
      options: options.iter().map(|x| x.to_string()).collect()
    }
  }

  fn create_embed(&self) -> Box<FnBox(EmbedBuilder) -> EmbedBuilder> {
    let name = self.author.clone();
    let options = self.options.iter()
      .enumerate()
      .map(|(i, x)| format!("{}⃣ – {}", i + 1, x))
      .collect::<Vec<_>>()
      .join("\n");
    let desc = format!("{}\n{}", self.text, options);
    box move |e: EmbedBuilder| {
      e
        .title(&format!("Poll by {}", name))
        .description(&desc)
    }
  }
}
<|endoftext|>


<commit_before>#![feature(use_extern_macros)]

extern crate clap;
extern crate jump;

use clap::{Arg, App, AppSettings};
use jump::Config;
use std::process;
use std::env;

macro_rules! exit_if_err {
    ($x:expr, $msg:expr) => (match $x {
        Ok(val) => val,
        Err(err) => {
            println!($msg, err);
            process::exit(1)
        }
    });
}

fn main() {
    let args = App::new("Jump Configure")
        .version(clap::crate_version!())
        .author(clap::crate_authors!())
        .about("Allows you to easily jump around your filesystem")
        .setting(AppSettings::UnifiedHelpMessage)
        .arg(Arg::with_name("marker")
             .help("The name of the marker")
             .index(1)
             .required(true))
        .get_matches();

    let config = exit_if_err!(Config::load(), "Failed to load config: {}");
    // We can unwrap this because it is marked as required
    let name = args.value_of("marker").unwrap();
    let marker_path = config.get_marker(name);
    match marker_path {
        None       => println!("Can't jump to {}", name),
        Some(path) => exit_if_err!(env::set_current_dir(&path), "Can't change directory: {}"),
    }

}
<commit_msg>Print out command for alias<commit_after>#![feature(use_extern_macros)]

extern crate clap;
extern crate jump;

use clap::{Arg, App, AppSettings};
use jump::Config;
use std::process;

macro_rules! exit_if_err {
    // TODO: print to stderr
    ($x:expr, $msg:expr) => (match $x {
        Ok(val) => val,
        Err(err) => {
            println!($msg, err);
            process::exit(1)
        }
    });
}

fn main() {
    let args = App::new("Jump Configure")
        .version(clap::crate_version!())
        .author(clap::crate_authors!())
        .about("Allows you to easily jump around your filesystem")
        .setting(AppSettings::UnifiedHelpMessage)
        .arg(Arg::with_name("marker")
             .help("The name of the marker")
             .index(1)
             .required(true))
        .get_matches();

    let config = exit_if_err!(Config::load(), "echo \"Failed to load config: {}\"");
    // We can unwrap this because it is marked as required
    let name = args.value_of("marker").unwrap();
    let marker_path = config.get_marker(name);
    match marker_path {
        None       => println!("echo \"Can't jump to {}\"", name),
        Some(path) => println!("cd \"{}\"", path),
    }

}
<|endoftext|>


<commit_before>extern crate lion;
extern crate nom;
extern crate linefeed;

use std::io::Error as IOError;

use nom::{Err::Error, Context::Code};
use linefeed::{Interface, ReadResult};
use lion::parser::{parse_program, parse_expr, Span};
use lion::interpreter::Interpreter;
use lion::ir::Number;

fn main() -> Result<(), IOError> {
    let input = include_str!("../../examples/units.lion");
    let program = parse_program(input).unwrap_or_else(|err| match err {
        Error(Code(Span { line, .. }, _)) =>
            panic!("Syntax Error: Line {}: {}", line, input.lines().nth(line as usize).unwrap()),
        _ => unreachable!(),
    });

    let mut interpreter = Interpreter::default();
    interpreter.load_decls(&program).unwrap();

    let reader = Interface::new("lion")?;
    reader.set_prompt("% ")?;

    while let ReadResult::Input(input) = reader.read_line()? {
        let input = input.trim();
        let expr = parse_expr(input).unwrap_or_else(|err| match err {
            Error(Code(Span { line, .. }, _)) =>
                panic!("Syntax Error: Line {}: {}", line, input.lines().nth(line as usize).unwrap()),
            _ => unreachable!(),
        });
        reader.add_history_unique(input.to_string());

        match interpreter.evaluate_expr(&expr) {
            Ok(Number {value, unit}) => {
                print!("{}", value);
                if !unit.is_unitless() {
                    print!(" ");
                    interpreter.print_unit(&unit);
                }
                println!();
            },
            Err(err) => println!("{:?}", err),
        }
    }

    Ok(())
}
<commit_msg>Rounding to 5 decimal places<commit_after>extern crate lion;
extern crate nom;
extern crate linefeed;

use std::io::Error as IOError;

use nom::{Err::Error, Context::Code};
use linefeed::{Interface, ReadResult};
use lion::parser::{parse_program, parse_expr, Span};
use lion::interpreter::Interpreter;
use lion::ir::Number;

fn main() -> Result<(), IOError> {
    let input = include_str!("../../examples/units.lion");
    let program = parse_program(input).unwrap_or_else(|err| match err {
        Error(Code(Span { line, .. }, _)) =>
            panic!("Syntax Error: Line {}: {}", line, input.lines().nth(line as usize).unwrap()),
        _ => unreachable!(),
    });

    let mut interpreter = Interpreter::default();
    interpreter.load_decls(&program).unwrap();

    let reader = Interface::new("lion")?;
    reader.set_prompt("% ")?;

    while let ReadResult::Input(input) = reader.read_line()? {
        let input = input.trim();
        let expr = parse_expr(input).unwrap_or_else(|err| match err {
            Error(Code(Span { line, .. }, _)) =>
                panic!("Syntax Error: Line {}: {}", line, input.lines().nth(line as usize).unwrap()),
            _ => unreachable!(),
        });
        reader.add_history_unique(input.to_string());

        match interpreter.evaluate_expr(&expr) {
            Ok(Number {value, unit}) => {
                print!("{}", value.round_dp(5));
                if !unit.is_unitless() {
                    print!(" ");
                    interpreter.print_unit(&unit);
                }
                println!();
            },
            Err(err) => println!("{:?}", err),
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
extern crate log;

use rustc::session::Session;
use rustc::middle::cstore::CrateStore;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use syntax::ast;
use std::path::PathBuf;

struct MiriCompilerCalls {
    default: Box<RustcDefaultCalls>,
    /// Whether to begin interpretation at the start_fn lang item or not
    ///
    /// If false, the interpretation begins at the `main` function
    start_fn: bool,
}

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default.early_callback(
            matches,
            sopts,
            cfg,
            descriptions,
            output,
        )
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default.no_input(
            matches,
            sopts,
            cfg,
            odir,
            ofile,
            descriptions,
        )
    }
    fn late_callback(
        &mut self,
        codegen_backend: &CodegenBackend,
        matches: &getopts::Matches,
        sess: &Session,
        cstore: &CrateStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile)
    }
    fn build_controller(
        self: Box<Self>,
        sess: &Session,
        matches: &getopts::Matches,
    ) -> CompileController<'a> {
        let this = *self;
        let mut control = this.default.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        let start_fn = this.start_fn;
        control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn));
        control.after_analysis.stop = Compilation::Stop;
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (
        String::from("miri"),
        syntax::feature_gate::AttributeType::Whitelisted,
    );
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bool) {
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a>(
            TyCtxt<'a, 'tcx, 'tcx>,
            &'a CompileState<'a, 'tcx>
        );
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::ItemKind::Fn(.., body_id) = i.node {
                    if i.attrs.iter().any(|attr| {
                        attr.name() == "test"
                    })
                    {
                        let did = self.0.hir.body_owner_def_id(body_id);
                        println!(
                            "running test: {}",
                            self.0.def_path_debug_str(did),
                        );
                        miri::eval_main(self.0, did, None);
                        self.1.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(
            &mut Visitor(tcx, state),
        );
    } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
        let entry_def_id = tcx.hir.local_def_id(entry_node_id);
        // Use start_fn lang item if we have -Zmiri-start-fn set
        let start_wrapper = if use_start_fn {
            Some(tcx.lang_items().start_fn().unwrap())
        } else {
            None
        };
        miri::eval_main(tcx, entry_def_id, start_wrapper);

        state.session.abort_if_errors();
    } else {
        println!("no main function found, assuming auxiliary build");
    }
}

fn init_logger() {
    let format = |formatter: &mut env_logger::fmt::Formatter, record: &log::Record| {
        use std::io::Write;
        if record.level() == log::Level::Trace {
            // prepend frame number
            let indentation = log_settings::settings().indentation;
            writeln!(
                formatter,
                "{indentation}:{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.module_path().unwrap_or("<unknown module>"),
                indentation = indentation,
                text = record.args(),
            )
        } else {
            writeln!(
                formatter,
                "{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.module_path().unwrap_or("<unknown_module>"),
                text = record.args(),
            )
        }
    };

    let mut builder = env_logger::Builder::new();
    builder.format(format).filter(
        None,
        log::LevelFilter::Info,
    );

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init();
}

fn find_sysroot() -> String {
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        return sysroot;
    }

    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "need to specify RUST_SYSROOT env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

fn main() {
    rustc_driver::init_rustc_env_logger();
    init_logger();
    let mut args: Vec<String> = std::env::args().collect();

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }

    let mut start_fn = false;
    args.retain(|arg| {
        if arg == "-Zmiri-start-fn" {
            start_fn = true;
            false
        } else {
            true
        }
    });

    let result = rustc_driver::run(move || {
        rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls {
            default: Box::new(RustcDefaultCalls),
            start_fn,
        }), None, None)
    });
    std::process::exit(result as i32);
}
<commit_msg>clarify error message when sysroot was not found<commit_after>#![feature(rustc_private)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
extern crate log;

use rustc::session::Session;
use rustc::middle::cstore::CrateStore;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use syntax::ast;
use std::path::PathBuf;

struct MiriCompilerCalls {
    default: Box<RustcDefaultCalls>,
    /// Whether to begin interpretation at the start_fn lang item or not
    ///
    /// If false, the interpretation begins at the `main` function
    start_fn: bool,
}

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default.early_callback(
            matches,
            sopts,
            cfg,
            descriptions,
            output,
        )
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default.no_input(
            matches,
            sopts,
            cfg,
            odir,
            ofile,
            descriptions,
        )
    }
    fn late_callback(
        &mut self,
        codegen_backend: &CodegenBackend,
        matches: &getopts::Matches,
        sess: &Session,
        cstore: &CrateStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile)
    }
    fn build_controller(
        self: Box<Self>,
        sess: &Session,
        matches: &getopts::Matches,
    ) -> CompileController<'a> {
        let this = *self;
        let mut control = this.default.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        let start_fn = this.start_fn;
        control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn));
        control.after_analysis.stop = Compilation::Stop;
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (
        String::from("miri"),
        syntax::feature_gate::AttributeType::Whitelisted,
    );
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bool) {
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a>(
            TyCtxt<'a, 'tcx, 'tcx>,
            &'a CompileState<'a, 'tcx>
        );
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::ItemKind::Fn(.., body_id) = i.node {
                    if i.attrs.iter().any(|attr| {
                        attr.name() == "test"
                    })
                    {
                        let did = self.0.hir.body_owner_def_id(body_id);
                        println!(
                            "running test: {}",
                            self.0.def_path_debug_str(did),
                        );
                        miri::eval_main(self.0, did, None);
                        self.1.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(
            &mut Visitor(tcx, state),
        );
    } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
        let entry_def_id = tcx.hir.local_def_id(entry_node_id);
        // Use start_fn lang item if we have -Zmiri-start-fn set
        let start_wrapper = if use_start_fn {
            Some(tcx.lang_items().start_fn().unwrap())
        } else {
            None
        };
        miri::eval_main(tcx, entry_def_id, start_wrapper);

        state.session.abort_if_errors();
    } else {
        println!("no main function found, assuming auxiliary build");
    }
}

fn init_logger() {
    let format = |formatter: &mut env_logger::fmt::Formatter, record: &log::Record| {
        use std::io::Write;
        if record.level() == log::Level::Trace {
            // prepend frame number
            let indentation = log_settings::settings().indentation;
            writeln!(
                formatter,
                "{indentation}:{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.module_path().unwrap_or("<unknown module>"),
                indentation = indentation,
                text = record.args(),
            )
        } else {
            writeln!(
                formatter,
                "{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.module_path().unwrap_or("<unknown_module>"),
                text = record.args(),
            )
        }
    };

    let mut builder = env_logger::Builder::new();
    builder.format(format).filter(
        None,
        log::LevelFilter::Info,
    );

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init();
}

fn find_sysroot() -> String {
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        return sysroot;
    }

    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "Could not find sysroot. Either set MIRI_SYSROOT at run-time, or at \
                     build-time specify RUST_SYSROOT env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

fn main() {
    rustc_driver::init_rustc_env_logger();
    init_logger();
    let mut args: Vec<String> = std::env::args().collect();

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }

    let mut start_fn = false;
    args.retain(|arg| {
        if arg == "-Zmiri-start-fn" {
            start_fn = true;
            false
        } else {
            true
        }
    });

    let result = rustc_driver::run(move || {
        rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls {
            default: Box::new(RustcDefaultCalls),
            start_fn,
        }), None, None)
    });
    std::process::exit(result as i32);
}
<|endoftext|>


<commit_before>use modular_flow::graph::*;
use modular_flow::context::*;
use std::thread;
use rustfft::FFTplanner;
use rustfft::num_complex::Complex;
use rustfft::num_traits::Zero;
use std::collections::VecDeque;
use apodize;
use std::iter;
use super::control::*;
use std::sync::Arc;

pub struct Stft {}

impl NodeDescriptor for Stft {
    const NAME: &'static str = "STFT";
    fn new(ctx: Arc<Context>) -> Arc<RemoteControl> {
        let id = ctx.graph().add_node(2, 2);
        let node_ctx = ctx.node_ctx(id).unwrap();
        let node = ctx.graph().node(id);

        // TODO add ports for params
        let size = 2048;
        let hop = 256;

        let remote_ctl = Arc::new(RemoteControl::new(
            node,
            vec![
                message::Desc {
                    name: "Add port",
                    args: vec![],
                },
                message::Desc {
                    name: "Remove port",
                    args: vec![],
                },
            ],
        ));

        let ctl = remote_ctl.clone();
        let window: Vec<T> = apodize::hanning_iter(size).map(|x| x.sqrt() as T).collect();
        thread::spawn(move || {
            let mut queues = vec![
                {
                    let mut q = VecDeque::<T>::new();
                    q.extend(vec![0.0; size - hop]);
                    q
                };
                node_ctx.node().in_ports().len()
            ];
            let mut input = vec![Complex::zero(); size];
            let mut output = vec![Complex::zero(); size];

            let mut planner = FFTplanner::new(false);
            let fft = planner.plan_fft(size);

            loop {
                ctl.poll_state_blocking();
                while let Some(msg) = ctl.recv_message() {
                    println!("{:?}", msg);
                }
                for ((in_port, out_port), queue) in
                    node_ctx.node().in_ports().iter().zip(node_ctx.node().out_ports()).zip(queues.iter_mut())
                {
                    let lock = node_ctx.lock();
                    lock.wait(|lock| lock.available::<T>(in_port.id()) >= hop);
                    queue.extend(lock.read_n::<T>(in_port.id(), hop).unwrap());
                    drop(lock);

                    for ((dst, src), mul) in input.iter_mut().zip(queue.iter()).zip(&window) {
                        dst.re = *src * mul;
                        dst.im = 0.0;
                    }
                    queue.drain(..hop);
                    fft.process(&mut input, &mut output);

                    node_ctx.lock().write(out_port.id(), &output[..output.len() / 2]).unwrap();
                }
            }
        });
        remote_ctl
    }
}

type T = f32; // fix this because generic numbers are so annoying

pub fn run_istft(ctx: NodeContext, size: usize, hop: usize) {
    let window: Vec<T> = apodize::hanning_iter(size).map(|x| x.sqrt() as T).collect();
    thread::spawn(move || {
        let mut queues = vec![
            {
                let mut q = VecDeque::<T>::new();
                q.extend(vec![0.0; size - hop]);
                q
            };
            ctx.node().in_ports().len()
        ];
        let mut output = vec![Complex::zero(); size];

        let mut planner = FFTplanner::new(true);
        let fft = planner.plan_fft(size);

        loop {
            for ((in_port, out_port), queue) in
                ctx.node().in_ports().iter().zip(ctx.node().out_ports()).zip(queues.iter_mut())
            {
                let lock = ctx.lock();
                lock.wait(|lock| lock.available::<Complex<T>>(in_port.id()) >= size / 2);
                let frame = lock.read_n::<Complex<T>>(in_port.id(), size / 2).unwrap();
                drop(lock);
                queue.extend(vec![0.0; hop]);
                let mut input: Vec<_> =
                    frame.iter().cloned().chain(iter::repeat(Complex::zero())).take(size).collect();
                fft.process(&mut input, &mut output);
                for ((src, dst), window) in output.iter().zip(queue.iter_mut()).zip(&window) {
                    *dst += src.re * *window / size as T / (size / hop) as T * 2.0;
                }
                let samples = queue.drain(..hop).collect::<Vec<_>>();
                ctx.lock().write(out_port.id(), &samples).unwrap();
            }
        }
    });
}

pub fn run_stft_render(ctx: NodeContext, size: usize) {
    use palette::*;
    use palette::pixel::*;

    let mut max = 1.0;
    let mut prev_frame = vec![Complex::<T>::zero(); size];
    thread::spawn(move || loop {
        // TODO rewrite this so we can drop the lock during processing
        let lock = ctx.lock();
        let mut frame = lock.node().in_ports().into_iter().map(|port| {
            lock.wait(|lock| lock.available::<Complex<T>>(port.id()) >= size);
            lock.read_n::<Complex<T>>(port.id(), size).unwrap()
        });
        let ch1 = frame.next().unwrap();
        let frame = frame.fold(ch1, |a, x| a.iter().zip(x.iter()).map(|(l, r)| l + r).collect());
        let out: Vec<_> = (0..size)
            .map(|idx| {
                let x = (idx as T / size as T * (size as T).log2()).exp2();
                let x_i = x as usize;

                // compute hue
                let hue1 = frame[x_i].arg() - prev_frame[x_i].arg();
                let hue2 = frame[(x_i + 1) % size].arg() - prev_frame[(x_i + 1) % size].arg();

                // compute intensity
                let norm1 = frame[x_i].norm();
                let norm2 = frame[(x_i + 1) % size].norm();
                max = T::max(norm1, max);
                max = T::max(norm2, max);
                let value1 = norm1 / max;
                let value2 = norm2 / max;

                // output colour
                let grad = Gradient::new(vec![
                    Hsv::new(RgbHue::from_radians(hue1), 1.0, value1),
                    Hsv::new(RgbHue::from_radians(hue2), 1.0, value2),
                ]);
                let (r, g, b, _): (T, T, T, T) = Srgb::linear_to_pixel(grad.get(x % 1.0));
                let (r, g, b) = (r * 255.0, g * 255.0, b * 255.0);
                (r as u32) << 24 | (g as u32) << 16 | (b as u32) << 8 | 0xFF
            })
            .collect();
        prev_frame = frame;
        lock.write(OutPortID(0), &out).unwrap();
    });
}
<commit_msg>don't forget zip takes the min<commit_after>use modular_flow::graph::*;
use modular_flow::context::*;
use std::thread;
use rustfft::FFTplanner;
use rustfft::num_complex::Complex;
use rustfft::num_traits::Zero;
use std::collections::VecDeque;
use apodize;
use std::iter;
use super::control::*;
use std::sync::Arc;

pub struct Stft {}

impl NodeDescriptor for Stft {
    const NAME: &'static str = "STFT";
    fn new(ctx: Arc<Context>) -> Arc<RemoteControl> {
        let id = ctx.graph().add_node(0, 0);
        let node_ctx = ctx.node_ctx(id).unwrap();
        let node = ctx.graph().node(id);

        // TODO add ports for params
        let size = 2048;
        let hop = 256;

        let remote_ctl = Arc::new(RemoteControl::new(
            node,
            vec![
                message::Desc {
                    name: "Add port",
                    args: vec![],
                },
                message::Desc {
                    name: "Remove port",
                    args: vec![],
                },
            ],
        ));

        let ctl = remote_ctl.clone();
        let window: Vec<T> = apodize::hanning_iter(size).map(|x| x.sqrt() as T).collect();
        thread::spawn(move || {
            let mut empty_q = VecDeque::<T>::new();
            empty_q.extend(vec![0.0; size - hop]);
            let mut queues = vec![];
            let mut input = vec![Complex::zero(); size];
            let mut output = vec![Complex::zero(); size];

            let mut planner = FFTplanner::new(false);
            let fft = planner.plan_fft(size);

            loop {
                while let Some(msg) = ctl.recv_message() {
                    match msg.desc.name {
                        "Add port" => {
                            node_ctx.node().push_in_port();
                            node_ctx.node().push_out_port();
                            queues.push(empty_q.clone());
                        }
                        "Remove port" => {
                            node_ctx.node().pop_in_port();
                            node_ctx.node().pop_out_port();
                            queues.pop();
                        }
                        _ => panic!()
                    }
                }
                match ctl.poll() {
                    ControlState::Stopped => break,
                    ControlState::Paused => continue,
                    _ => (),
                }
                for ((in_port, out_port), queue) in
                    node_ctx.node().in_ports().iter().zip(node_ctx.node().out_ports()).zip(queues.iter_mut())
                {
                    let lock = node_ctx.lock();
                    lock.wait(|lock| lock.available::<T>(in_port.id()) >= hop);
                    queue.extend(lock.read_n::<T>(in_port.id(), hop).unwrap());
                    drop(lock);

                    for ((dst, src), mul) in input.iter_mut().zip(queue.iter()).zip(&window) {
                        dst.re = *src * mul;
                        dst.im = 0.0;
                    }
                    queue.drain(..hop);
                    fft.process(&mut input, &mut output);

                    node_ctx.lock().write(out_port.id(), &output[..output.len() / 2]).unwrap();
                }
            }
        });
        remote_ctl
    }
}

type T = f32; // fix this because generic numbers are so annoying

pub fn run_istft(ctx: NodeContext, size: usize, hop: usize) {
    let window: Vec<T> = apodize::hanning_iter(size).map(|x| x.sqrt() as T).collect();
    thread::spawn(move || {
        let mut queues = vec![
            {
                let mut q = VecDeque::<T>::new();
                q.extend(vec![0.0; size - hop]);
                q
            };
            ctx.node().in_ports().len()
        ];
        let mut output = vec![Complex::zero(); size];

        let mut planner = FFTplanner::new(true);
        let fft = planner.plan_fft(size);

        loop {
            for ((in_port, out_port), queue) in
                ctx.node().in_ports().iter().zip(ctx.node().out_ports()).zip(queues.iter_mut())
            {
                let lock = ctx.lock();
                lock.wait(|lock| lock.available::<Complex<T>>(in_port.id()) >= size / 2);
                let frame = lock.read_n::<Complex<T>>(in_port.id(), size / 2).unwrap();
                drop(lock);
                queue.extend(vec![0.0; hop]);
                let mut input: Vec<_> =
                    frame.iter().cloned().chain(iter::repeat(Complex::zero())).take(size).collect();
                fft.process(&mut input, &mut output);
                for ((src, dst), window) in output.iter().zip(queue.iter_mut()).zip(&window) {
                    *dst += src.re * *window / size as T / (size / hop) as T * 2.0;
                }
                let samples = queue.drain(..hop).collect::<Vec<_>>();
                ctx.lock().write(out_port.id(), &samples).unwrap();
            }
        }
    });
}

pub fn run_stft_render(ctx: NodeContext, size: usize) {
    use palette::*;
    use palette::pixel::*;

    let mut max = 1.0;
    let mut prev_frame = vec![Complex::<T>::zero(); size];
    thread::spawn(move || loop {
        // TODO rewrite this so we can drop the lock during processing
        let lock = ctx.lock();
        let mut frame = lock.node().in_ports().into_iter().map(|port| {
            lock.wait(|lock| lock.available::<Complex<T>>(port.id()) >= size);
            lock.read_n::<Complex<T>>(port.id(), size).unwrap()
        });
        let ch1 = frame.next().unwrap();
        let frame = frame.fold(ch1, |a, x| a.iter().zip(x.iter()).map(|(l, r)| l + r).collect());
        let out: Vec<_> = (0..size)
            .map(|idx| {
                let x = (idx as T / size as T * (size as T).log2()).exp2();
                let x_i = x as usize;

                // compute hue
                let hue1 = frame[x_i].arg() - prev_frame[x_i].arg();
                let hue2 = frame[(x_i + 1) % size].arg() - prev_frame[(x_i + 1) % size].arg();

                // compute intensity
                let norm1 = frame[x_i].norm();
                let norm2 = frame[(x_i + 1) % size].norm();
                max = T::max(norm1, max);
                max = T::max(norm2, max);
                let value1 = norm1 / max;
                let value2 = norm2 / max;

                // output colour
                let grad = Gradient::new(vec![
                    Hsv::new(RgbHue::from_radians(hue1), 1.0, value1),
                    Hsv::new(RgbHue::from_radians(hue2), 1.0, value2),
                ]);
                let (r, g, b, _): (T, T, T, T) = Srgb::linear_to_pixel(grad.get(x % 1.0));
                let (r, g, b) = (r * 255.0, g * 255.0, b * 255.0);
                (r as u32) << 24 | (g as u32) << 16 | (b as u32) << 8 | 0xFF
            })
            .collect();
        prev_frame = frame;
        lock.write(OutPortID(0), &out).unwrap();
    });
}
<|endoftext|>