<commit_before>
use argparse;
use amqp::{ConsumerCallBackFn, Session, Table, Basic, Channel, Options, Consumer};
use amqp::protocol;
use std::default::Default;
use rustc_serialize::json;
use std::slice;

#[derive(Debug, Default, RustcDecodable, RustcEncodable, Clone)]
pub struct ParticipantPort {
    pub id: String, // port name
    pub queue: String, // the associated message queue
    // FIXME: support. Is a keyword so needs some special handling   type: String, // datatype, ex: "boolean"
    // options: queue options as specified by the message queue implementation
    // description?? TODO: standardize
}

#[derive(Debug, Default, RustcDecodable, RustcEncodable, Clone)]
pub struct ParticipantInfo {
    pub id: String, // unique name
    pub role: String ,// role participant has
    pub component: String, // component the participant is instance of
    pub label: Option<String>, // (optional) short human-readable description
    pub icon: Option<String>, // (optional)
    pub inports: Vec<ParticipantPort>,
    pub outports: Vec<ParticipantPort>,
}

pub struct InfoBuilder {
    info: ParticipantInfo
}

impl InfoBuilder {
    pub fn new(component: &str) -> InfoBuilder {
        InfoBuilder {
            info:  ParticipantInfo {
                id: "".to_string(), // FIXME: use Option
                role: "".to_string(), // FIXME: use Option
                icon: None,
                label: None,
                component: component.to_string(),
                inports: vec! [],
                outports: vec! [],
            }
        }
    }

    pub fn label(&mut self, label: &str) -> &mut InfoBuilder {
        self.info.label = Some(label.to_string());
        self
    }

    pub fn inport(&mut self, id: &str) -> &mut InfoBuilder {
        let port = ParticipantPort { id: id.to_string(), queue: "".to_string() };
        self.info.inports.push(port);
        self
    }
    pub fn outport(&mut self, id: &str) -> &mut InfoBuilder {
        let port = ParticipantPort { id: id.to_string(), queue: "".to_string() };
        self.info.outports.push(port);
        self
    }
    pub fn build(&self) -> ParticipantInfo {
        return self.info.clone();
    }
}

type SendFunction = fn(String, Vec<u8>);
pub type ProcessFunction = fn(Vec<u8>) -> Result<Vec<u8>, Vec<u8>>;
pub struct Participant {
    pub info: ParticipantInfo,
    pub process: ProcessFunction,
}

struct Connection {
    session: Session,
    channel: Channel,
}

// FIXME: wrap in protocol/command/payload envelope
fn create_queue_and_send(channel: &mut Channel, queue_name: &str, payload: String) {

    let queue_declare = channel.queue_declare(queue_name, false, true, false, false, false, Table::new());
    queue_declare.expect("queue creation failed");
    let content_type = Some("application/json".to_string());
    let props = protocol::basic::BasicProperties { content_type: content_type, ..Default::default() };
    debug!("sending on {}: {}", queue_name, payload);
    let res = channel.basic_publish("", queue_name, true, false, props, payload.into_bytes());
    res.expect("send on new queue failed");
}

fn send_discovery(channel: &mut Channel, info: &ParticipantInfo) {
    let queue_name = "fbp"; // TODO: use an exchange istead, requires protocol change in msgflo

    let payload = json::encode(&info).unwrap();
    create_queue_and_send(channel, queue_name, payload);
    info!("sent participant discovery: {}  {}({})", info.id, info.role, info.component);
}

struct PortConsumer {
    process: ProcessFunction,
    portname: String,
    outqueue: String, // FIXME: allow sending on any port, also multiple times
}

fn send_out(channel: &mut Channel, exchange: String, data: Vec<u8>) {

    let routing_key = "".to_string();
    let content_type = Some("application/json".to_string()); // TODO: should be parameter
    let props = protocol::basic::BasicProperties { content_type: content_type, ..Default::default() };
    let s = channel.basic_publish(exchange, routing_key, true, false, props, data);
    s.expect("failed to send");
    debug!("sent output");
}

impl Consumer for PortConsumer {
    fn handle_delivery(&mut self,
                       channel: &mut Channel,
                       deliver: protocol::basic::Deliver,
                       headers: protocol::basic::BasicProperties,
                       body: Vec<u8>) {

        debug!("calling process()");
        let f = self.process;
        let res = f(body);
        debug!("process() returned");

        if res.is_ok() {
            debug!("ACKing and sending");
            send_out(channel, self.outqueue.to_string(), res.unwrap());
            let r = channel.basic_ack(deliver.delivery_tag, false);
        } else {
            error!("process() errored");
            let r = channel.basic_nack(deliver.delivery_tag, true, true);
        }
        // FIXME: send error data
    }
}

// FIXME: actually call ProcessFunction
fn setup_inport(participant: &Participant, port: &ParticipantPort, connection: &mut Connection) {
    debug!("setup inport: {}", port.queue.to_string());

    let consumer = PortConsumer {
        process: participant.process,
        portname: port.id.to_string(),
        outqueue: participant.info.outports[0].queue.to_string(),
    };

    // create
    let declare = connection.channel.queue_declare(port.queue.to_string(), false, true, false, false, false, Table::new());
    declare.expect("inport queue creation failed");

    // subscribe
    let q = port.queue.to_string();
    let cons = connection.channel.basic_consume(consumer, q,
                                                "".to_string(), false, false, false, false, Table::new());

    cons.expect("iport setup failed");

    debug!("inport setup done: {:?}, {:?}", port.id.to_string(), port.queue.to_string());
}

fn setup_outport(participant: &Participant, port: &ParticipantPort, connection: &mut Connection) {

    let exchange_type = "fanout".to_string();
    let declare = connection.channel.exchange_declare(port.queue.to_string(), exchange_type,
                                                    false, true, false, false, false, Table::new());
    declare.expect("outport setup failed");

    debug!("setup outport done: {:?}, {:?}", port.id.to_string(), port.queue.to_string());
}

fn start_participant(participant: &Participant, options: &ParticipantOptions) -> Connection {

    let mut session = Session::open_url(&options.broker).expect("Can't create AMQP session");
    let mut channel = session.open_channel(1).expect("could not open AMQP channel");

    let mut conn = Connection { session: session, channel: channel };

    // setup ports
    setup_inport(&participant, &participant.info.inports[0], &mut conn);
    setup_outport(&participant, &participant.info.outports[0], &mut conn);

    // send MsgFlo participant discovery message
    send_discovery(&mut conn.channel, &participant.info);

    return conn;
}

fn stop_participant(participant: &Participant, connection: &mut Connection) {

    let closed = connection.channel.close(200, "Bye".to_string());
    connection.session.close(200, "Good Bye".to_string());
}

#[derive(Debug)]
struct ParticipantOptions {
    role: String,
    broker: String,
}

impl Default for ParticipantOptions {
    fn default() -> ParticipantOptions {
        use rand::{thread_rng, Rng};

        let id: String = thread_rng().gen_ascii_chars().take(5).collect();
        ParticipantOptions {
            broker: "amqp://localhost//".to_string(),
            role: "".to_string(), // TODO: allow anonymous, format!("msgflo-rust-{}", id),
        }
    }
}

fn parse(options: &mut ParticipantOptions) {

    use argparse::{StoreTrue, Store};
    let mut parser = argparse::ArgumentParser::new();

    parser.refer(&mut options.role)
        .add_option(&["--role"], Store, "Participant role name");
    parser.refer(&mut options.broker)
        .add_option(&["--broker"], Store, "Address of messaging broker")
        .envvar("MSGFLO_BROKER");

    parser.parse_args_or_exit(); // XXX: should return out
}

// XXX: seems rust-amqp makes program hangs forever if error occurs / channel is borked?
// TODO: pass port info in/out of process()
// TODO: nicer way to declare ports? ideally they are enums not stringly typed?
pub fn main(p: Participant) {

    let mut options = ParticipantOptions { .. Default::default() };
    parse(&mut options);

    if options.role == "" {
        options.role = p.info.role.to_string();
    }

    let mut c = start_participant(&p, &options);
    println!("{}({}) started", &options.role, &p.info.component);
    c.channel.start_consuming();

    stop_participant(&p, &mut c);
}

<commit_msg>Start of proper info merging with options<commit_after>
use argparse;
use amqp::{ConsumerCallBackFn, Session, Table, Basic, Channel, Options, Consumer};
use amqp::protocol;
use std::default::Default;
use rustc_serialize::json;
use std::slice;

#[derive(Debug, Default, RustcDecodable, RustcEncodable, Clone)]
pub struct ParticipantPort {
    pub id: String, // port name
    pub queue: String, // the associated message queue
    // FIXME: support. Is a keyword so needs some special handling   type: String, // datatype, ex: "boolean"
    // options: queue options as specified by the message queue implementation
    // description?? TODO: standardize
}

#[derive(Debug, Default, RustcDecodable, RustcEncodable, Clone)]
pub struct ParticipantInfo {
    pub id: String, // unique name
    pub role: String ,// role participant has
    pub component: String, // component the participant is instance of
    pub label: Option<String>, // (optional) short human-readable description
    pub icon: Option<String>, // (optional)
    pub inports: Vec<ParticipantPort>,
    pub outports: Vec<ParticipantPort>,
}

pub struct InfoBuilder {
    info: ParticipantInfo
}

impl InfoBuilder {
    pub fn new(component: &str) -> InfoBuilder {
        InfoBuilder {
            info:  ParticipantInfo { .. Default::default() }
        }
    }

    pub fn label(&mut self, label: &str) -> &mut InfoBuilder {
        self.info.label = Some(label.to_string());
        self
    }

    pub fn inport(&mut self, id: &str) -> &mut InfoBuilder {
        let port = ParticipantPort { id: id.to_string(), queue: "".to_string() };
        self.info.inports.push(port);
        self
    }
    pub fn outport(&mut self, id: &str) -> &mut InfoBuilder {
        let port = ParticipantPort { id: id.to_string(), queue: "".to_string() };
        self.info.outports.push(port);
        self
    }
    pub fn build(&self) -> ParticipantInfo {
        return self.info.clone();
    }
}

type SendFunction = fn(String, Vec<u8>);
pub type ProcessFunction = fn(Vec<u8>) -> Result<Vec<u8>, Vec<u8>>;
pub struct Participant {
    pub info: ParticipantInfo,
    pub process: ProcessFunction,
}

struct Connection {
    session: Session,
    channel: Channel,
}

// FIXME: wrap in protocol/command/payload envelope
fn create_queue_and_send(channel: &mut Channel, queue_name: &str, payload: String) {

    let queue_declare = channel.queue_declare(queue_name, false, true, false, false, false, Table::new());
    queue_declare.expect("queue creation failed");
    let content_type = Some("application/json".to_string());
    let props = protocol::basic::BasicProperties { content_type: content_type, ..Default::default() };
    debug!("sending on {}: {}", queue_name, payload);
    let res = channel.basic_publish("", queue_name, true, false, props, payload.into_bytes());
    res.expect("send on new queue failed");
}

fn send_discovery(channel: &mut Channel, info: &ParticipantInfo) {
    let queue_name = "fbp"; // TODO: use an exchange istead, requires protocol change in msgflo

    let payload = json::encode(&info).unwrap();
    create_queue_and_send(channel, queue_name, payload);
    info!("sent participant discovery: {}  {}({})", info.id, info.role, info.component);
}

struct PortConsumer {
    process: ProcessFunction,
    portname: String,
    outqueue: String, // FIXME: allow sending on any port, also multiple times
}

fn send_out(channel: &mut Channel, exchange: String, data: Vec<u8>) {

    let routing_key = "".to_string();
    let content_type = Some("application/json".to_string()); // TODO: should be parameter
    let props = protocol::basic::BasicProperties { content_type: content_type, ..Default::default() };
    let s = channel.basic_publish(exchange, routing_key, true, false, props, data);
    s.expect("failed to send");
    debug!("sent output");
}

impl Consumer for PortConsumer {
    fn handle_delivery(&mut self,
                       channel: &mut Channel,
                       deliver: protocol::basic::Deliver,
                       headers: protocol::basic::BasicProperties,
                       body: Vec<u8>) {

        debug!("calling process()");
        let f = self.process;
        let res = f(body);
        debug!("process() returned");

        if res.is_ok() {
            debug!("ACKing and sending");
            send_out(channel, self.outqueue.to_string(), res.unwrap());
            let r = channel.basic_ack(deliver.delivery_tag, false);
        } else {
            error!("process() errored");
            let r = channel.basic_nack(deliver.delivery_tag, true, true);
        }
        // FIXME: send error data
    }
}

// FIXME: actually call ProcessFunction
fn setup_inport(participant: &Participant, port: &ParticipantPort, connection: &mut Connection) {
    debug!("setup inport: {}", port.queue.to_string());

    let consumer = PortConsumer {
        process: participant.process,
        portname: port.id.to_string(),
        outqueue: participant.info.outports[0].queue.to_string(),
    };

    // create
    let declare = connection.channel.queue_declare(port.queue.to_string(), false, true, false, false, false, Table::new());
    declare.expect("inport queue creation failed");

    // subscribe
    let q = port.queue.to_string();
    let cons = connection.channel.basic_consume(consumer, q,
                                                "".to_string(), false, false, false, false, Table::new());

    cons.expect("iport setup failed");

    debug!("inport setup done: {:?}, {:?}", port.id.to_string(), port.queue.to_string());
}

fn setup_outport(participant: &Participant, port: &ParticipantPort, connection: &mut Connection) {

    let exchange_type = "fanout".to_string();
    let declare = connection.channel.exchange_declare(port.queue.to_string(), exchange_type,
                                                    false, true, false, false, false, Table::new());
    declare.expect("outport setup failed");

    debug!("setup outport done: {:?}, {:?}", port.id.to_string(), port.queue.to_string());
}

fn start_participant(participant: &Participant, options: &ParticipantOptions) -> Connection {

    let mut session = Session::open_url(&options.broker).expect("Can't create AMQP session");
    let mut channel = session.open_channel(1).expect("could not open AMQP channel");

    let mut conn = Connection { session: session, channel: channel };

    // setup ports
    setup_inport(&participant, &participant.info.inports[0], &mut conn);
    setup_outport(&participant, &participant.info.outports[0], &mut conn);

    // send MsgFlo participant discovery message
    send_discovery(&mut conn.channel, &participant.info);

    return conn;
}

fn stop_participant(participant: &Participant, connection: &mut Connection) {

    let closed = connection.channel.close(200, "Bye".to_string());
    connection.session.close(200, "Good Bye".to_string());
}

#[derive(Debug)]
struct ParticipantOptions {
    role: String,
    broker: String,
}

impl Default for ParticipantOptions {
    fn default() -> ParticipantOptions {

        ParticipantOptions {
            broker: "amqp://localhost//".to_string(),
            role: "".to_string(),
        }
    }
}

fn normalize_info(info: &ParticipantInfo, options: &ParticipantOptions) -> ParticipantInfo {
    use rand::{thread_rng, Rng};

    let mut new = info.clone();

    // normalize role name
    if options.role != "" {
        new.role = options.role.to_string();
    }
    if new.role == "" {
        let role_rnd: String = thread_rng().gen_ascii_chars().take(5).collect();
        new.role = format!("msgflo-rust-{}", role_rnd);
    }

    // generate ID
    let id_rnd: String = thread_rng().gen_ascii_chars().take(5).collect();
    new.id = format!("{}-{}", new.role, id_rnd);

    // generate port defaults

    // FIXME: allow to specify queue explicitly
    //new.inports =

    return new;
}

fn default_queue(role: String, port_name: String) -> String {
    return role + "." + &port_name.to_uppercase();
}

fn parse(options: &mut ParticipantOptions) {

    use argparse::{StoreTrue, Store};
    let mut parser = argparse::ArgumentParser::new();

    parser.refer(&mut options.role)
        .add_option(&["--role"], Store, "Participant role name");
    parser.refer(&mut options.broker)
        .add_option(&["--broker"], Store, "Address of messaging broker")
        .envvar("MSGFLO_BROKER");

    parser.parse_args_or_exit(); // XXX: should return out
}

// XXX: seems rust-amqp makes program hangs forever if error occurs / channel is borked?
// TODO: pass port info in/out of process()
// TODO: nicer way to declare ports? ideally they are enums not stringly typed?
pub fn main(p: Participant) {

    let mut options = ParticipantOptions { .. Default::default() };
    parse(&mut options);

    normalize_info(&p.info, &options);

    let mut c = start_participant(&p, &options);
    println!("{}({}) started", &options.role, &p.info.component);
    c.channel.start_consuming();

    stop_participant(&p, &mut c);
}

<|endoftext|>


<commit_before>// Queries.
use crate::bounding_volume::{BoundingSphere, AABB};
use crate::math::{Isometry, Vector};
use na::{self, RealField, Unit};
use crate::query::{PointQuery, RayCast};
use crate::shape::{CompositeShape, ConvexPolyhedron, DeformableShape, FeatureId, SupportMap};
use std::ops::Deref;
use std::sync::Arc;
use downcast_rs::Downcast;

pub trait ShapeClone<N: RealField> {
    fn clone_box(&self) -> Box<Shape<N>> {
        unimplemented!()
    }
}

impl<N: RealField, T: 'static + Shape<N> + Clone> ShapeClone<N> for T {
    fn clone_box(&self) -> Box<Shape<N>> {
        Box::new(self.clone())
    }
}

/// Trait implemented by all shapes supported by ncollide.
///
/// This allows dynamic inspection of the shape capabilities.
pub trait Shape<N: RealField>: Send + Sync + Downcast + ShapeClone<N> {
    /// The AABB of `self` transformed by `m`.
    #[inline]
    fn aabb(&self, m: &Isometry<N>) -> AABB<N>;

    /// The AABB of `self`.
    #[inline]
    fn local_aabb(&self) -> AABB<N> {
        self.aabb(&Isometry::identity())
    }

    /// The bounding sphere of `self` transformed by `m`.
    #[inline]
    fn bounding_sphere(&self, m: &Isometry<N>) -> BoundingSphere<N> {
        let aabb = self.aabb(m);
        BoundingSphere::new(aabb.center(), aabb.half_extents().norm())
    }

    /// The bounding sphere of `self`.
    #[inline]
    fn local_bounding_sphere(&self) -> BoundingSphere<N> {
        let aabb = self.local_aabb();
        BoundingSphere::new(aabb.center(), aabb.half_extents().norm())
    }

    /// Check if if the feature `_feature` of the `i-th` subshape of `self` transformed by `m` has a tangent
    /// cone that contains `dir` at the point `pt`.
    // NOTE: for the moment, we assume the tangent cone is the same for the whole feature.
    #[inline]
    fn tangent_cone_contains_dir(
        &self,
        _feature: FeatureId,
        _m: &Isometry<N>,
        _deformations: Option<&[N]>,
        _dir: &Unit<Vector<N>>,
    ) -> bool;

    /// Returns the id of the subshape containing the specified feature.
    ///
    /// If several subshape contains the same feature, any one is returned.
    fn subshape_containing_feature(&self, _i: FeatureId) -> usize {
        0
    }

    /// The `RayCast` implementation of `self`.
    #[inline]
    fn as_ray_cast(&self) -> Option<&RayCast<N>> {
        None
    }

    /// The `PointQuery` implementation of `self`.
    #[inline]
    fn as_point_query(&self) -> Option<&PointQuery<N>> {
        None
    }

    /// The convex polyhedron representation of `self` if applicable.
    #[inline]
    fn as_convex_polyhedron(&self) -> Option<&ConvexPolyhedron<N>> {
        None
    }

    /// The support mapping of `self` if applicable.
    #[inline]
    fn as_support_map(&self) -> Option<&SupportMap<N>> {
        None
    }

    /// The composite shape representation of `self` if applicable.
    #[inline]
    fn as_composite_shape(&self) -> Option<&CompositeShape<N>> {
        None
    }

    /// The deformable shape representation of `self` if applicable.
    #[inline]
    fn as_deformable_shape(&self) -> Option<&DeformableShape<N>> {
        None
    }

    /// The mutable deformable shape representation of `self` if applicable.
    #[inline]
    fn as_deformable_shape_mut(&mut self) -> Option<&mut DeformableShape<N>> {
        None
    }

    /// Whether `self` uses a convex polyhedron representation.
    #[inline]
    fn is_convex_polyhedron(&self) -> bool {
        self.as_convex_polyhedron().is_some()
    }

    /// Whether `self` uses a support-mapping based representation.
    #[inline]
    fn is_support_map(&self) -> bool {
        self.as_support_map().is_some()
    }

    /// Whether `self` uses a composite shape-based representation.
    #[inline]
    fn is_composite_shape(&self) -> bool {
        self.as_composite_shape().is_some()
    }

    /// Whether `self` uses a composite shape-based representation.
    #[inline]
    fn is_deformable_shape(&self) -> bool {
        self.as_deformable_shape().is_some()
    }
}

impl_downcast!(Shape<N> where N: RealField);

/// Trait for casting shapes to its exact represetation.
impl<N: RealField> Shape<N> {
    /// Tests if this shape has a specific type `T`.
    #[inline]
    pub fn is_shape<T: Shape<N>>(&self) -> bool {
        self.is::<T>()
    }

    /// Performs the cast.
    #[inline]
    pub fn as_shape<T: Shape<N>>(&self) -> Option<&T> {
        self.downcast_ref()
    }
}

impl<N: RealField> Clone for Box<Shape<N>> {
    fn clone(&self) -> Box<Shape<N>> {
        self.clone_box()
    }
}

/// A shared handle to an abstract shape.
///
/// This can be mutated using COW.
#[derive(Clone)]
pub struct ShapeHandle<N: RealField>(Arc<Box<Shape<N>>>);

impl<N: RealField> ShapeHandle<N> {
    /// Creates a sharable shape handle from a shape.
    #[inline]
    pub fn new<S: Shape<N>>(shape: S) -> ShapeHandle<N> {
        ShapeHandle(Arc::new(Box::new(shape)))
    }

    pub(crate) fn make_mut(&mut self) -> &mut Shape<N> {
        &mut **Arc::make_mut(&mut self.0)
    }
}

impl<N: RealField> AsRef<Shape<N>> for ShapeHandle<N> {
    #[inline]
    fn as_ref(&self) -> &Shape<N> {
        &*self.deref()
    }
}

impl<N: RealField> Deref for ShapeHandle<N> {
    type Target = Shape<N>;

    #[inline]
    fn deref(&self) -> &Shape<N> {
        &**self.0.deref()
    }
}<commit_msg>Add ShapeHandle::new_from_box<commit_after>// Queries.
use crate::bounding_volume::{BoundingSphere, AABB};
use crate::math::{Isometry, Vector};
use na::{self, RealField, Unit};
use crate::query::{PointQuery, RayCast};
use crate::shape::{CompositeShape, ConvexPolyhedron, DeformableShape, FeatureId, SupportMap};
use std::ops::Deref;
use std::sync::Arc;
use downcast_rs::Downcast;

pub trait ShapeClone<N: RealField> {
    fn clone_box(&self) -> Box<Shape<N>> {
        unimplemented!()
    }
}

impl<N: RealField, T: 'static + Shape<N> + Clone> ShapeClone<N> for T {
    fn clone_box(&self) -> Box<Shape<N>> {
        Box::new(self.clone())
    }
}

/// Trait implemented by all shapes supported by ncollide.
///
/// This allows dynamic inspection of the shape capabilities.
pub trait Shape<N: RealField>: Send + Sync + Downcast + ShapeClone<N> {
    /// The AABB of `self` transformed by `m`.
    #[inline]
    fn aabb(&self, m: &Isometry<N>) -> AABB<N>;

    /// The AABB of `self`.
    #[inline]
    fn local_aabb(&self) -> AABB<N> {
        self.aabb(&Isometry::identity())
    }

    /// The bounding sphere of `self` transformed by `m`.
    #[inline]
    fn bounding_sphere(&self, m: &Isometry<N>) -> BoundingSphere<N> {
        let aabb = self.aabb(m);
        BoundingSphere::new(aabb.center(), aabb.half_extents().norm())
    }

    /// The bounding sphere of `self`.
    #[inline]
    fn local_bounding_sphere(&self) -> BoundingSphere<N> {
        let aabb = self.local_aabb();
        BoundingSphere::new(aabb.center(), aabb.half_extents().norm())
    }

    /// Check if if the feature `_feature` of the `i-th` subshape of `self` transformed by `m` has a tangent
    /// cone that contains `dir` at the point `pt`.
    // NOTE: for the moment, we assume the tangent cone is the same for the whole feature.
    #[inline]
    fn tangent_cone_contains_dir(
        &self,
        _feature: FeatureId,
        _m: &Isometry<N>,
        _deformations: Option<&[N]>,
        _dir: &Unit<Vector<N>>,
    ) -> bool;

    /// Returns the id of the subshape containing the specified feature.
    ///
    /// If several subshape contains the same feature, any one is returned.
    fn subshape_containing_feature(&self, _i: FeatureId) -> usize {
        0
    }

    /// The `RayCast` implementation of `self`.
    #[inline]
    fn as_ray_cast(&self) -> Option<&RayCast<N>> {
        None
    }

    /// The `PointQuery` implementation of `self`.
    #[inline]
    fn as_point_query(&self) -> Option<&PointQuery<N>> {
        None
    }

    /// The convex polyhedron representation of `self` if applicable.
    #[inline]
    fn as_convex_polyhedron(&self) -> Option<&ConvexPolyhedron<N>> {
        None
    }

    /// The support mapping of `self` if applicable.
    #[inline]
    fn as_support_map(&self) -> Option<&SupportMap<N>> {
        None
    }

    /// The composite shape representation of `self` if applicable.
    #[inline]
    fn as_composite_shape(&self) -> Option<&CompositeShape<N>> {
        None
    }

    /// The deformable shape representation of `self` if applicable.
    #[inline]
    fn as_deformable_shape(&self) -> Option<&DeformableShape<N>> {
        None
    }

    /// The mutable deformable shape representation of `self` if applicable.
    #[inline]
    fn as_deformable_shape_mut(&mut self) -> Option<&mut DeformableShape<N>> {
        None
    }

    /// Whether `self` uses a convex polyhedron representation.
    #[inline]
    fn is_convex_polyhedron(&self) -> bool {
        self.as_convex_polyhedron().is_some()
    }

    /// Whether `self` uses a support-mapping based representation.
    #[inline]
    fn is_support_map(&self) -> bool {
        self.as_support_map().is_some()
    }

    /// Whether `self` uses a composite shape-based representation.
    #[inline]
    fn is_composite_shape(&self) -> bool {
        self.as_composite_shape().is_some()
    }

    /// Whether `self` uses a composite shape-based representation.
    #[inline]
    fn is_deformable_shape(&self) -> bool {
        self.as_deformable_shape().is_some()
    }
}

impl_downcast!(Shape<N> where N: RealField);

/// Trait for casting shapes to its exact represetation.
impl<N: RealField> Shape<N> {
    /// Tests if this shape has a specific type `T`.
    #[inline]
    pub fn is_shape<T: Shape<N>>(&self) -> bool {
        self.is::<T>()
    }

    /// Performs the cast.
    #[inline]
    pub fn as_shape<T: Shape<N>>(&self) -> Option<&T> {
        self.downcast_ref()
    }
}

impl<N: RealField> Clone for Box<Shape<N>> {
    fn clone(&self) -> Box<Shape<N>> {
        self.clone_box()
    }
}

/// A shared handle to an abstract shape.
///
/// This can be mutated using COW.
#[derive(Clone)]
pub struct ShapeHandle<N: RealField>(Arc<Box<Shape<N>>>);

impl<N: RealField> ShapeHandle<N> {
    /// Creates a sharable shape handle from a shape.
    #[inline]
    pub fn new<S: Shape<N>>(shape: S) -> ShapeHandle<N> {
        ShapeHandle(Arc::new(Box::new(shape)))
    }

    /// Creates a sharable shape handle from a shape trait object.
    pub fn new_from_box(shape: Box<Shape<N>>) -> ShapeHandle<N> {
        ShapeHandle(Arc::new(shape))
    }

    pub(crate) fn make_mut(&mut self) -> &mut Shape<N> {
        &mut **Arc::make_mut(&mut self.0)
    }
}

impl<N: RealField> AsRef<Shape<N>> for ShapeHandle<N> {
    #[inline]
    fn as_ref(&self) -> &Shape<N> {
        &*self.deref()
    }
}

impl<N: RealField> Deref for ShapeHandle<N> {
    type Target = Shape<N>;

    #[inline]
    fn deref(&self) -> &Shape<N> {
        &**self.0.deref()
    }
}<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;

use result::Result;
use error::AnnotationErrorKind as AEK;

use module_path::ModuleEntryPath;

pub trait Annotateable {

    /// Add an annotation to `Self`, that is a `FileLockEntry` which is linked to `Self` (link as in
    /// libimagentrylink).
    ///
    /// This `Annotation` is stored in the Store itself.
    fn annotate(&self, store: &Store) -> Result<Annotation> {
        self.annotate_with_path_generator(store, DefaultAnnotationPathGenerator::new())
    }

    /// Add an annotation to `Self`, that is a `FileLockEntry` which is linked to `Self` (link as in
    /// libimagentrylink).
    ///
    /// This `Annotation` is stored in the Store itself.
    ///
    /// The `pg` is a AnnotationPathGenerator object which is used to generate a StoreId
    fn annotate_with_path_generator(&self, store: &Store, pg: &AnnotationPathGenerator) -> Result<Annotation>;

    /// List annotations of a Annotateable
    ///
    /// This lists only annotations that are generated via the `DefaultAnnotationPathGenerator`
    fn annotations(&self) -> Result<Vec<StoreId>>;

}

/// A AnnotationPathGenerator generates a unique path for the annotation to be generated.
pub trait AnnotationPathGenerator {
    fn generate_annotation_path(&self) -> Result<StoreId>;
}

/// The DefaultAnnotationPathGenerator generates unique StoreIds for Annotations, where the
/// collection the annotations are stored in is `/annotation/`.
pub struct DefaultAnnotationPathGenerator;

impl AnnotationPathGenerator for DefaultAnnotationPathGenerator {

    fn generate_annotation_path(&self) -> Result<StoreId> {
        let id = Uuid::new_v4();
        ModuleEntryPath::new(format!("{}", id)).map_err_into(AEK::StoreIdGenerationError)
    }

}

pub struct Annotation<'a>(FileLockEntry<'a>);

impl Annotateable for FileLockEntry {

    fn annotate_with_path_generator(&self, store: &Store, pg: &AnnotationPathGenerator)
        -> Result<Annotation>
    {
        pb.generate_annotation_path()
            .and_then(|id| store.create(id).map_err_into(AEK::StoreWriteError))
            .and_then(|mut fle| {
                self.add_internal_link(&mut fle)
                    .map_err_into(AEK::LinkingError)
                    .map(|_| fle)
            })
            .map(Annotation)
    }

    /// Get the annotations of a FileLockEntry
    ///
    /// Returns the pathes to the annotations, not the annotations itself.
    fn annotations(&self) -> Result<Vec<StoreId>> {
        self.get_internal_links()
            .map_err_into(AEK::LinkError)
            .map(|v| v.iter_into()
                .filter(|id| id.components()
                    .next()
                    .map(|fst| match fst {
                        Component::Normal(ref s) => s == ANNOTATION_COLLECTION_NAME,
                        _ => false,
                    })
                    .unwrap_or(false)
                )
                .collect::<Vec<StoreId>>();
            )
    }

}
<commit_msg>Add Annotateable::remove_annotation*()<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;

use result::Result;
use error::AnnotationErrorKind as AEK;

use module_path::ModuleEntryPath;

pub trait Annotateable {

    /// Add an annotation to `Self`, that is a `FileLockEntry` which is linked to `Self` (link as in
    /// libimagentrylink).
    ///
    /// This `Annotation` is stored in the Store itself.
    fn annotate(&self, store: &Store) -> Result<Annotation> {
        self.annotate_with_path_generator(store, DefaultAnnotationPathGenerator::new())
    }

    /// Add an annotation to `Self`, that is a `FileLockEntry` which is linked to `Self` (link as in
    /// libimagentrylink).
    ///
    /// This `Annotation` is stored in the Store itself.
    ///
    /// The `pg` is a AnnotationPathGenerator object which is used to generate a StoreId
    fn annotate_with_path_generator(&self, store: &Store, pg: &AnnotationPathGenerator) -> Result<Annotation>;

    /// List annotations of a Annotateable
    ///
    /// This lists only annotations that are generated via the `DefaultAnnotationPathGenerator`
    fn annotations(&self) -> Result<Vec<StoreId>>;

    /// Remove an annotation by its ID
    fn remove_annotation(&mut self, ann_id: &str) -> Result<()>;

    /// Remove an annotation and remove the annotation object from the store, if there's no more
    /// link to it.
    fn remove_annotation_with_gc(&mut self, ann_id: &str, store: &Store) -> Result<()>;

}

/// A AnnotationPathGenerator generates a unique path for the annotation to be generated.
pub trait AnnotationPathGenerator {
    fn generate_annotation_path(&self) -> Result<StoreId>;
}

/// The DefaultAnnotationPathGenerator generates unique StoreIds for Annotations, where the
/// collection the annotations are stored in is `/annotation/`.
pub struct DefaultAnnotationPathGenerator;

impl AnnotationPathGenerator for DefaultAnnotationPathGenerator {

    fn generate_annotation_path(&self) -> Result<StoreId> {
        let id = Uuid::new_v4();
        ModuleEntryPath::new(format!("{}", id)).map_err_into(AEK::StoreIdGenerationError)
    }

}

pub struct Annotation<'a>(FileLockEntry<'a>);

impl Annotateable for FileLockEntry {

    fn annotate_with_path_generator(&self, store: &Store, pg: &AnnotationPathGenerator)
        -> Result<Annotation>
    {
        pb.generate_annotation_path()
            .and_then(|id| store.create(id).map_err_into(AEK::StoreWriteError))
            .and_then(|mut fle| {
                self.add_internal_link(&mut fle)
                    .map_err_into(AEK::LinkingError)
                    .map(|_| fle)
            })
            .map(Annotation)
    }

    /// Get the annotations of a FileLockEntry
    ///
    /// Returns the pathes to the annotations, not the annotations itself.
    fn annotations(&self) -> Result<Vec<StoreId>> {
        self.get_internal_links()
            .map_err_into(AEK::LinkError)
            .map(|v| v.iter_into()
                .filter(|id| id.components()
                    .next()
                    .map(|fst| match fst {
                        Component::Normal(ref s) => s == ANNOTATION_COLLECTION_NAME,
                        _ => false,
                    })
                    .unwrap_or(false)
                )
                .collect::<Vec<StoreId>>();
            )
    }

    /// Remove an annotation by its ID
    fn remove_annotation(&mut self, ann_id: &str) -> Result<()> {
        unimplemented!()
    }

    /// Remove an annotation and remove the annotation object from the store, if there's no more
    /// link to it.
    fn remove_annotation_with_gc(&mut self, ann_id: &str, store: &Store) -> Result<()> {
        unimplemented!()
    }

}
<|endoftext|>


<commit_before>
use Error;
use Result;
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};

#[derive(Debug)]
pub struct CMAP {
    encoding_subtable: EncodingSubtable,
    cmap_offset: usize,
}

impl CMAP {
    pub fn from_data(data: &[u8], offset: usize) -> Result<Self> {

        if offset >= data.len() || offset + 4 > data.len() {
            return Err(Error::Malformed);
        }

        // +2 skip version field.
        let number_subtables = BigEndian::read_u16(&data[offset + 2..]) as usize;
        let data = &data[offset + 4..];
        if number_subtables * (2 + 2 + 4) > data.len() {
            return Err(Error::Malformed);
        }

        let mut encoding_subtables: Vec<_> = (0..number_subtables).filter_map(|n| {
            let z = n as usize * 8;
            let platform_id = BigEndian::read_u16(&data[z + 0..]);
            let platform_specific_id = BigEndian::read_u16(&data[z + 2..]);
            let offset = BigEndian::read_u32(&data[z + 4..]);
            Platform::new(platform_id, platform_specific_id).map(|platform| {
                EncodingSubtable { platform: platform, offset: offset}
            })
        }).collect();

        encoding_subtables.sort_by(|a, b| a.order().cmp(&b.order()));

        if encoding_subtables.is_empty() {
            return Err(Error::CMAPEncodingSubtableIsNotSupported);
        }

        Ok(CMAP {
            encoding_subtable: encoding_subtables.first().unwrap().clone(),
            cmap_offset: offset,
        })
    }

    pub fn index_map(&self) -> usize {
        self.encoding_subtable.offset as usize + self.cmap_offset
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
struct EncodingSubtable {
    platform: Platform,
    offset: u32,
}

impl EncodingSubtable {
    /// Defines an order in which the encoding subtables should be selected.
    fn order(&self) -> u32 {
        use self::Platform::*;
        use self::UnicodeEncodingId::*;
        use self::MicrosoftEncodingId::*;

        match self.platform {
            Unicode(Unicode20) => 0,
            Unicode(Unicode20BMPOnly) => 1,
            Unicode(Version11Semantics) => 1,
            Unicode(DefaultSemantics) => 1,
            Microsoft(UnicodeUCS4) => 2,
            Microsoft(UnicodeUCS2) => 3,
            Microsoft(Symbol) => 4,
            _ => 10,
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Platform {
    Unicode(UnicodeEncodingId),
    Microsoft(MicrosoftEncodingId),
}

impl Platform {
    fn new(platform_id: u16, platform_specific_id: u16) -> Option<Self> {
        use self::Platform::*;
        use self::UnicodeEncodingId::*;
        use self::MicrosoftEncodingId::*;

        match platform_id {
            0 => match platform_specific_id {
                0 => Some(Unicode(DefaultSemantics)),
                1 => Some(Unicode(Version11Semantics)),
                3 => Some(Unicode(Unicode20BMPOnly)),
                4 => Some(Unicode(Unicode20)),
                5 => Some(Unicode(UnicodeVariationSequences)),
                6 => Some(Unicode(FullUnicodeCoverage)),
                _ => None,
            },
            3 => match platform_specific_id {
                0 => Some(Microsoft(Symbol)),
                1 => Some(Microsoft(UnicodeUCS2)),
                2 => Some(Microsoft(ShiftJIS)),
                3 => Some(Microsoft(PRC)),
                4 => Some(Microsoft(BigFive)),
                5 => Some(Microsoft(Johab)),
                10 => Some(Microsoft(UnicodeUCS4)),
                _ => None,
            },
            _ => None,
        }
    }
}

#[repr(u16)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum UnicodeEncodingId {
    DefaultSemantics = 0,
    Version11Semantics = 1,
    Unicode20BMPOnly = 3,
    Unicode20 = 4,
    UnicodeVariationSequences = 5,
    FullUnicodeCoverage = 6,
}

#[repr(u16)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum MicrosoftEncodingId {
    Symbol = 0,
    UnicodeUCS2 = 1,
    ShiftJIS = 2,
    PRC = 3,
    BigFive = 4,
    Johab = 5,
    UnicodeUCS4 = 10
}

#[derive(Debug)]
struct Format0 {
    format: u16,
    length: u16,
    language: u16,
    glyph_index_array: Vec<u8>,
}

impl Format0 {
    fn from_data(data: &[u8], offset: usize) -> Result<Self> {
        const SIZE: usize = 262;
        if offset + SIZE > data.len() {
            return Err(Error::Malformed);
        }

        let format = BigEndian::read_u16(&data[offset..]);
        let length = BigEndian::read_u16(&data[offset + 2..]);
        if length as usize != SIZE {
            return Err(Error::Malformed);
        }
        let language = BigEndian::read_u16(&data[offset + 4..]);

        Ok(Format0 {
            format: format,
            length: length,
            language: language,
            glyph_index_array: data[offset + 6..SIZE].to_owned(),
        })
    }

    fn index_for_code(&self, code: usize) -> Option<usize> {
        self.glyph_index_array.get(code).map(|&i| i as usize)
    }
}

#[derive(Debug)]
struct Format6 {
    format: u16,
    length: u16,
    language: u16,
    first_code: u16,
    entry_count: u16,
    raw_glyph_index_array: Vec<u8>,
}

impl Format6 {
    fn from_data(data: &[u8], offset: usize) -> Result<Self> {
        if offset + 2 * 5 > data.len() {
            return Err(Error::Malformed);
        }

        let format = BigEndian::read_u16(&data[offset..]);
        let length = BigEndian::read_u16(&data[offset + 2..]);
        let language = BigEndian::read_u16(&data[offset + 4..]);
        let first_code = BigEndian::read_u16(&data[offset + 6..]);
        let entry_count = BigEndian::read_u16(&data[offset + 8..]);

        let size = entry_count as usize * 2;
        if offset + 2 * 5 + size > data.len() {
            return Err(Error::Malformed);
        }

        Ok(Format6 {
            format: format,
            length: length,
            language: language,
            first_code: first_code,
            entry_count: entry_count,
            raw_glyph_index_array: data[offset + 2 * 5..size].to_owned(),
        })
    }

    fn index_for_code(&self, code: usize) -> Option<usize> {
        let first_code = self.first_code as usize;
        let entry_count = self.entry_count as usize;
        if code < first_code || code >= first_code + entry_count {
            None
        } else {
            let offset = (code - first_code) * 2;
            if offset >= self.raw_glyph_index_array.len() {
                None
            } else {
                Some(BigEndian::read_u16(&self.raw_glyph_index_array[offset..]) as usize)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use Error::*;
    use expectest::prelude::*;

    #[test]
    fn smoke() {
        let data = ::utils::read_file("tests/Tuffy_Bold.ttf");
        let offset = ::utils::find_table_offset(&data, 0, b"cmap").unwrap().unwrap();

        let _ = CMAP::from_data(&data, offset).unwrap();
    }
}
<commit_msg>Implement cmap's format 12 and format 13.<commit_after>
use Error;
use Result;
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};

#[derive(Debug)]
pub struct CMAP {
    encoding_subtable: EncodingSubtable,
    cmap_offset: usize,
}

impl CMAP {
    pub fn from_data(data: &[u8], offset: usize) -> Result<Self> {

        if offset >= data.len() || offset + 4 > data.len() {
            return Err(Error::Malformed);
        }

        // +2 skip version field.
        let number_subtables = BigEndian::read_u16(&data[offset + 2..]) as usize;
        let data = &data[offset + 4..];
        if number_subtables * (2 + 2 + 4) > data.len() {
            return Err(Error::Malformed);
        }

        let mut encoding_subtables: Vec<_> = (0..number_subtables).filter_map(|n| {
            let z = n as usize * 8;
            let platform_id = BigEndian::read_u16(&data[z + 0..]);
            let platform_specific_id = BigEndian::read_u16(&data[z + 2..]);
            let offset = BigEndian::read_u32(&data[z + 4..]);
            Platform::new(platform_id, platform_specific_id).map(|platform| {
                EncodingSubtable { platform: platform, offset: offset}
            })
        }).collect();

        encoding_subtables.sort_by(|a, b| a.order().cmp(&b.order()));

        if encoding_subtables.is_empty() {
            return Err(Error::CMAPEncodingSubtableIsNotSupported);
        }

        Ok(CMAP {
            encoding_subtable: encoding_subtables.first().unwrap().clone(),
            cmap_offset: offset,
        })
    }

    pub fn index_map(&self) -> usize {
        self.encoding_subtable.offset as usize + self.cmap_offset
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
struct EncodingSubtable {
    platform: Platform,
    offset: u32,
}

impl EncodingSubtable {
    /// Defines an order in which the encoding subtables should be selected.
    fn order(&self) -> u32 {
        use self::Platform::*;
        use self::UnicodeEncodingId::*;
        use self::MicrosoftEncodingId::*;

        match self.platform {
            Unicode(Unicode20) => 0,
            Unicode(Unicode20BMPOnly) => 1,
            Unicode(Version11Semantics) => 1,
            Unicode(DefaultSemantics) => 1,
            Microsoft(UnicodeUCS4) => 2,
            Microsoft(UnicodeUCS2) => 3,
            Microsoft(Symbol) => 4,
            _ => 10,
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Platform {
    Unicode(UnicodeEncodingId),
    Microsoft(MicrosoftEncodingId),
}

impl Platform {
    fn new(platform_id: u16, platform_specific_id: u16) -> Option<Self> {
        use self::Platform::*;
        use self::UnicodeEncodingId::*;
        use self::MicrosoftEncodingId::*;

        match platform_id {
            0 => match platform_specific_id {
                0 => Some(Unicode(DefaultSemantics)),
                1 => Some(Unicode(Version11Semantics)),
                3 => Some(Unicode(Unicode20BMPOnly)),
                4 => Some(Unicode(Unicode20)),
                5 => Some(Unicode(UnicodeVariationSequences)),
                6 => Some(Unicode(FullUnicodeCoverage)),
                _ => None,
            },
            3 => match platform_specific_id {
                0 => Some(Microsoft(Symbol)),
                1 => Some(Microsoft(UnicodeUCS2)),
                2 => Some(Microsoft(ShiftJIS)),
                3 => Some(Microsoft(PRC)),
                4 => Some(Microsoft(BigFive)),
                5 => Some(Microsoft(Johab)),
                10 => Some(Microsoft(UnicodeUCS4)),
                _ => None,
            },
            _ => None,
        }
    }
}

#[repr(u16)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum UnicodeEncodingId {
    DefaultSemantics = 0,
    Version11Semantics = 1,
    Unicode20BMPOnly = 3,
    Unicode20 = 4,
    UnicodeVariationSequences = 5,
    FullUnicodeCoverage = 6,
}

#[repr(u16)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum MicrosoftEncodingId {
    Symbol = 0,
    UnicodeUCS2 = 1,
    ShiftJIS = 2,
    PRC = 3,
    BigFive = 4,
    Johab = 5,
    UnicodeUCS4 = 10
}

#[derive(Debug)]
struct Format0 {
    format: u16,
    length: u16,
    language: u16,
    glyph_index_array: Vec<u8>,
}

impl Format0 {
    fn from_data(data: &[u8], offset: usize) -> Result<Self> {
        const SIZE: usize = 262;
        if offset + SIZE > data.len() {
            return Err(Error::Malformed);
        }

        let format = BigEndian::read_u16(&data[offset..]);
        let length = BigEndian::read_u16(&data[offset + 2..]);
        if length as usize != SIZE {
            return Err(Error::Malformed);
        }
        let language = BigEndian::read_u16(&data[offset + 4..]);

        Ok(Format0 {
            format: format,
            length: length,
            language: language,
            glyph_index_array: data[offset + 6..SIZE].to_owned(),
        })
    }

    fn index_for_code(&self, code: usize) -> Option<usize> {
        self.glyph_index_array.get(code).map(|&i| i as usize)
    }
}

#[derive(Debug)]
struct Format6 {
    format: u16,
    length: u16,
    language: u16,
    first_code: u16,
    entry_count: u16,
    raw_glyph_index_array: Vec<u8>,
}

impl Format6 {
    fn from_data(data: &[u8], offset: usize) -> Result<Self> {
        if offset + 2 * 5 > data.len() {
            return Err(Error::Malformed);
        }

        let format = BigEndian::read_u16(&data[offset..]);
        let length = BigEndian::read_u16(&data[offset + 2..]);
        let language = BigEndian::read_u16(&data[offset + 4..]);
        let first_code = BigEndian::read_u16(&data[offset + 6..]);
        let entry_count = BigEndian::read_u16(&data[offset + 8..]);

        let size = entry_count as usize * 2;
        if offset + 2 * 5 + size > data.len() {
            return Err(Error::Malformed);
        }

        Ok(Format6 {
            format: format,
            length: length,
            language: language,
            first_code: first_code,
            entry_count: entry_count,
            raw_glyph_index_array: data[offset + 2 * 5..size].to_owned(),
        })
    }

    fn index_for_code(&self, code: usize) -> Option<usize> {
        let first_code = self.first_code as usize;
        let entry_count = self.entry_count as usize;
        if code < first_code || code >= first_code + entry_count {
            None
        } else {
            let offset = (code - first_code) * 2;
            if offset >= self.raw_glyph_index_array.len() {
                None
            } else {
                Some(BigEndian::read_u16(&self.raw_glyph_index_array[offset..]) as usize)
            }
        }
    }
}

#[derive(Debug, Copy, Clone)]
struct GroupFormat1213 {
    start_char_code: u32,
    end_char_code: u32,
    start_glyph_code: u32,
}

#[derive(Debug, Default)]
struct Format1213 {
    format: u32,
    length: u32,
    language: u32,
    n_groups: u32,
    groups: Vec<GroupFormat1213>,
}

impl Format1213 {
    fn from_data(data: &[u8], offset: usize) -> Result<Self> {
        if offset + 4 * 4 > data.len() {
            return Err(Error::Malformed);
        }

        let mut f = Format1213::default();
        f.format = BigEndian::read_u32(&data[offset..]);
        f.length = BigEndian::read_u32(&data[offset + 4..]);
        f.language = BigEndian::read_u32(&data[offset + 8..]);
        f.n_groups = BigEndian::read_u32(&data[offset + 12..]);

        if offset + f.n_groups as usize * 12 > data.len() {
            return Err(Error::Malformed);
        }

        let data = &data[offset + 4 * 4..];
        for n in 0..f.n_groups {
            let z = n as usize * 3 * 4;
            let sc = BigEndian::read_u32(&data[z..]);
            let ec = BigEndian::read_u32(&data[z + 4..]);
            let sg = BigEndian::read_u32(&data[z + 8..]);
            f.groups.push(GroupFormat1213 {
                start_char_code: sc,
                end_char_code: ec,
                start_glyph_code: sg
            });
        }

        Ok(f)
    }

    fn index_for_code(&self, code: usize) -> Option<usize> {
        use std::cmp::Ordering::*;

        let group = self.groups.binary_search_by(|group| {
            if code < group.start_char_code as usize {
                Greater
            } else if code > group.end_char_code as usize {
                Less
            } else {
                Equal
            }
        }).ok().map(|i| self.groups[i]);

        group.map(|group| {
            if self.format == 12 << 16 { // format 12.0
                code - group.start_char_code as usize + group.start_glyph_code as usize
            } else {
                group.start_glyph_code as usize
            }
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use Error::*;
    use expectest::prelude::*;

    #[test]
    fn smoke() {
        let data = ::utils::read_file("tests/Tuffy_Bold.ttf");
        let offset = ::utils::find_table_offset(&data, 0, b"cmap").unwrap().unwrap();

        let _ = CMAP::from_data(&data, offset).unwrap();
    }
}
<|endoftext|>


<commit_before>use binary::{
    async_trait::async_trait,
    eyre::{bail, Result},
    Binary, BinaryTrait,
};

pub struct PackBinary {}

#[async_trait]
impl BinaryTrait for PackBinary {
    #[rustfmt::skip]
    fn spec(&self) -> Binary {
        Binary::new(
            "pack",
            &[],
            &[],
            // Release list at https://github.com/buildpacks/pack/releases
            // Current strategy is to support the latest patch version of the last three minor version.
            &[
                "0.23.0",
                "0.22.0",
                "0.21.1"
            ],
        )
    }

    async fn install_version(&self, version: &str, os: &str, arch: &str) -> Result<()> {
        let url = format!(
            "https://github.com/buildpacks/pack/releases/download/v{version}/pack-v{version}-",
            version = version
        ) + match os {
            "linux" => "linux.tgz",
            "macos" => match arch {
                "arm" => "macos-arm64.tgz",
                _ => "macos.tgz",
            },
            "windows" => "windows.zip",
            _ => bail!("Unable to determine Node download URL"),
        };
        let archive = self.download(&url, None, None).await?;

        let dest = self.dir(Some(version.into()), true)?;
        self.extract(&archive, 0, &dest)?;
        self.executables(&dest, &["pack"])?;

        Ok(())
    }
}
<commit_msg>chore(Pack binary): Fix error message<commit_after>use binary::{
    async_trait::async_trait,
    eyre::{bail, Result},
    Binary, BinaryTrait,
};

pub struct PackBinary {}

#[async_trait]
impl BinaryTrait for PackBinary {
    #[rustfmt::skip]
    fn spec(&self) -> Binary {
        Binary::new(
            "pack",
            &[],
            &[],
            // Release list at https://github.com/buildpacks/pack/releases
            // Current strategy is to support the latest patch version of the last three minor version.
            &[
                "0.23.0",
                "0.22.0",
                "0.21.1"
            ],
        )
    }

    async fn install_version(&self, version: &str, os: &str, arch: &str) -> Result<()> {
        let url = format!(
            "https://github.com/buildpacks/pack/releases/download/v{version}/pack-v{version}-",
            version = version
        ) + match os {
            "linux" => "linux.tgz",
            "macos" => match arch {
                "arm" => "macos-arm64.tgz",
                _ => "macos.tgz",
            },
            "windows" => "windows.zip",
            _ => bail!(
                "Installation of `pack` for operating system `{}` is not supported",
                os
            ),
        };
        let archive = self.download(&url, None, None).await?;

        let dest = self.dir(Some(version.into()), true)?;
        self.extract(&archive, 0, &dest)?;
        self.executables(&dest, &["pack"])?;

        Ok(())
    }
}
<|endoftext|>


<commit_before>
extern crate rand;
extern crate test;

use ndarray::{arr2, arr1, stack};
use dataframe::*;
use test::Bencher;
use ndarray::Array;
use rand::distributions::Range;
use ndarray_rand::RandomExt;
use std::rc::Rc;
use rand::{thread_rng, Rng};
use std::collections::{HashMap, BTreeMap};
use chrono::*;
use util::types::*;
use util::error::*;
use adapters::aggregate::*;
use adapters::transform::*;
use util::traits::*;
use std::f64::NAN;
use ndarray::Axis;
use adapters::join::*;
use mixedtypes::*;

#[test]
fn outer_left_join() {
    let a = arr2(&[["Alice"], ["Bob"]]);
    let left: DataFrame<InnerType, OuterType> =
        DataFrame::new(a).index(&[1, 2]).unwrap().columns(&["a"]).unwrap();
    let b = arr2(&[["Programmer"]]);
    let right: DataFrame<InnerType, OuterType> =
        DataFrame::new(b).index(&[1]).unwrap().columns(&["b"]).unwrap();
    let res = left.outer_left_join(&right).as_df();
    let expected_data = arr2(&[[InnerType::Str(String::from("Alice")),
                                InnerType::Str(String::from("Programmer"))],
                               [InnerType::Str(String::from("Bob")), InnerType::Empty]]);
    let expected =
        DataFrame::new(expected_data).index(&[1, 2]).unwrap().columns(&["a", "b"]).unwrap();
    assert_eq!(res.unwrap(), expected);

}
#[test]
fn inner_join() {
    let a = arr2(&[["Alice"], ["Bob"], ["Suchin"]]);
    let left: DataFrame<InnerType, OuterType> =
        DataFrame::new(a).index(&[1, 2, 3]).unwrap().columns(&["a"]).unwrap();
    let b = arr2(&[["Programmer"], ["Data Scientist"]]);
    let right = DataFrame::new(b).index(&[1, 3]).unwrap().columns(&["b"]).unwrap();
    let res = left.inner_left_join(&right).as_df();
    let expected_data = arr2(&[[InnerType::Str(String::from("Alice")),
                                InnerType::Str(String::from("Programmer"))],
                               [InnerType::Str(String::from("Suchin")),
                                InnerType::Str(String::from("Data Scientist"))]]);
    let expected =
        DataFrame::new(expected_data).index(&[1, 3]).unwrap().columns(&["a", "b"]).unwrap();
    assert_eq!(res.unwrap(), expected);
}

#[test]
fn dataframe_creation() {
    let a = arr2(&[[2., 3.], [3., 4.]]);
    let df: Result<DataFrame<f64, String>> = DataFrame::new(a).columns(&["a", "b"]);
    assert!(df.is_ok())
}

#[test]
fn dataframe_creation_failure() {
    let a = Array::random((2, 5), Range::new(0., 10.));
    let df: Result<DataFrame<f64, String>> = DataFrame::new(a).columns(&["1", "2"]);
    assert!(df.is_err())
}

#[test]
fn dataframe_select() {
    let a = arr2(&[[2., 3.], [3., 4.]]);
    let df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
    let select_idx = vec!["a"];
    let z = df.select(&select_idx[..], UtahAxis::Column).as_df();
    let col = df.data.column(0).clone();
    let expected = DataFrame::from_array(col.to_owned(), UtahAxis::Column)
        .columns(&["a"])
        .unwrap();
    assert_eq!(z.unwrap(), expected);

    let select_idx = vec!["0"];
    let z = df.select(&select_idx[..], UtahAxis::Row).as_df();
    let col = df.data.row(0).clone();
    let expected = DataFrame::from_array(col.to_owned(), UtahAxis::Row)
        .index(&["0"])
        .unwrap()
        .columns(&["a", "b"])
        .unwrap();
    assert_eq!(z.unwrap(), expected);
}

#[test]
fn dataframe_remove() {
    let a = arr2(&[[2., 3.], [3., 4.]]);
    let df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
    let remove_idx = vec!["a"];
    let z = df.remove(&remove_idx[..], UtahAxis::Column).as_df();
    let col = df.data.column(1).clone();
    let expected = DataFrame::from_array(col.to_owned(), UtahAxis::Column)
        .columns(&["b"])
        .unwrap();
    assert_eq!(z.unwrap(), expected);

    let remove_idx = vec!["0"];
    let z = df.remove(&remove_idx[..], UtahAxis::Row).as_df();
    let row = df.data.row(1).clone();
    let expected = DataFrame::from_array(row.to_owned(), UtahAxis::Row)
        .index(&["1"])
        .unwrap()
        .columns(&["a", "b"])
        .unwrap();
    assert_eq!(z.unwrap(), expected);
}

#[test]
fn dataframe_append() {
    {
        let a = arr2(&[[2., 3.], [3., 4.]]);
        let mut df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
        let col = df.select(&["a"], UtahAxis::Column).as_array().unwrap();
        let z = df.append("c", col.view(), UtahAxis::Column).as_df();
        let b = arr2(&[[2., 3., 2.], [3., 3., 4.]]);
        let expected = DataFrame::new(b)
            .columns(&["c", "a", "b"])
            .unwrap();
        assert_eq!(z.unwrap(), expected);
    }
    {
        let a = arr2(&[[2., 3.], [3., 4.]]);
        let mut df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
        let col = df.select(&["1"], UtahAxis::Row).as_array().unwrap();
        let z = df.append("2", col.view(), UtahAxis::Row).as_df();
        let b = arr2(&[[3., 4.], [2., 3.], [3., 4.]]);
        let expected = DataFrame::new(b)
            .columns(&["a", "b"])
            .unwrap()
            .index(&["2", "0", "1"])
            .unwrap();
        assert_eq!(z.unwrap(), expected);
    }
}

#[test]
fn dataframe_mapdf() {
    {
        let a = arr2(&[[2., 3.], [3., 4.]]);
        let mut df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
        let z: Vec<(String, Row<f64>)> = df.map(|x| x * 2.0, UtahAxis::Row).collect();
        let b = arr2(&[[4., 6.], [6., 8.]]);
        let mut expected = Vec::new();
        expected.push(("0".to_string(), b.row(0).to_owned()));
        expected.push(("1".to_string(), b.row(1).to_owned()));
        assert_eq!(z, expected);
    }
    {
        let a = arr2(&[[2., 3.], [3., 4.]]);
        let mut df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
        let z: Vec<(String, Row<f64>)> = df.map(|x| x * 2.0, UtahAxis::Column).collect();
        let b = arr2(&[[4., 6.], [6., 8.]]);
        let mut expected = Vec::new();
        expected.push(("a".to_string(), b.row(0).to_owned()));
        expected.push(("b".to_string(), b.row(1).to_owned()));
        assert_eq!(z, expected);
    }
}
<commit_msg>added more tests<commit_after>
extern crate rand;
extern crate test;

use ndarray::{arr2, arr1, stack};
use dataframe::*;
use test::Bencher;
use ndarray::Array;
use rand::distributions::Range;
use ndarray_rand::RandomExt;
use std::rc::Rc;
use rand::{thread_rng, Rng};
use std::collections::{HashMap, BTreeMap};
use chrono::*;
use util::types::*;
use util::error::*;
use adapters::aggregate::*;
use adapters::transform::*;
use util::traits::*;
use std::f64::NAN;
use ndarray::Axis;
use adapters::join::*;
use mixedtypes::*;

#[test]
fn outer_left_join() {
    let a = arr2(&[["Alice"], ["Bob"]]);
    let left: DataFrame<InnerType, OuterType> =
        DataFrame::new(a).index(&[1, 2]).unwrap().columns(&["a"]).unwrap();
    let b = arr2(&[["Programmer"]]);
    let right: DataFrame<InnerType, OuterType> =
        DataFrame::new(b).index(&[1]).unwrap().columns(&["b"]).unwrap();
    let res = left.outer_left_join(&right).as_df();
    let expected_data = arr2(&[[InnerType::Str(String::from("Alice")),
                                InnerType::Str(String::from("Programmer"))],
                               [InnerType::Str(String::from("Bob")), InnerType::Empty]]);
    let expected =
        DataFrame::new(expected_data).index(&[1, 2]).unwrap().columns(&["a", "b"]).unwrap();
    assert_eq!(res.unwrap(), expected);

}
#[test]
fn inner_join() {
    let a = arr2(&[["Alice"], ["Bob"], ["Suchin"]]);
    let left: DataFrame<InnerType, OuterType> =
        DataFrame::new(a).index(&[1, 2, 3]).unwrap().columns(&["a"]).unwrap();
    let b = arr2(&[["Programmer"], ["Data Scientist"]]);
    let right = DataFrame::new(b).index(&[1, 3]).unwrap().columns(&["b"]).unwrap();
    let res = left.inner_left_join(&right).as_df();
    let expected_data = arr2(&[[InnerType::Str(String::from("Alice")),
                                InnerType::Str(String::from("Programmer"))],
                               [InnerType::Str(String::from("Suchin")),
                                InnerType::Str(String::from("Data Scientist"))]]);
    let expected =
        DataFrame::new(expected_data).index(&[1, 3]).unwrap().columns(&["a", "b"]).unwrap();
    assert_eq!(res.unwrap(), expected);
}

#[test]
fn dataframe_creation() {
    let a = arr2(&[[2., 3.], [3., 4.]]);
    let df: Result<DataFrame<f64, String>> = DataFrame::new(a).columns(&["a", "b"]);
    assert!(df.is_ok())
}

#[test]
fn dataframe_creation_failure() {
    let a = Array::random((2, 5), Range::new(0., 10.));
    let df: Result<DataFrame<f64, String>> = DataFrame::new(a).columns(&["1", "2"]);
    assert!(df.is_err())
}

#[test]
fn dataframe_select() {
    let a = arr2(&[[2., 3.], [3., 4.]]);
    let df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
    let select_idx = vec!["a"];
    let z = df.select(&select_idx[..], UtahAxis::Column).as_df();
    let col = df.data.column(0).clone();
    let expected = DataFrame::from_array(col.to_owned(), UtahAxis::Column)
        .columns(&["a"])
        .unwrap();
    assert_eq!(z.unwrap(), expected);

    let select_idx = vec!["0"];
    let z = df.select(&select_idx[..], UtahAxis::Row).as_df();
    let col = df.data.row(0).clone();
    let expected = DataFrame::from_array(col.to_owned(), UtahAxis::Row)
        .index(&["0"])
        .unwrap()
        .columns(&["a", "b"])
        .unwrap();
    assert_eq!(z.unwrap(), expected);
}

#[test]
fn dataframe_remove() {
    let a = arr2(&[[2., 3.], [3., 4.]]);
    let df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
    let remove_idx = vec!["a"];
    let z = df.remove(&remove_idx[..], UtahAxis::Column).as_df();
    let col = df.data.column(1).clone();
    let expected = DataFrame::from_array(col.to_owned(), UtahAxis::Column)
        .columns(&["b"])
        .unwrap();
    assert_eq!(z.unwrap(), expected);

    let remove_idx = vec!["0"];
    let z = df.remove(&remove_idx[..], UtahAxis::Row).as_df();
    let row = df.data.row(1).clone();
    let expected = DataFrame::from_array(row.to_owned(), UtahAxis::Row)
        .index(&["1"])
        .unwrap()
        .columns(&["a", "b"])
        .unwrap();
    assert_eq!(z.unwrap(), expected);
}

#[test]
fn dataframe_append() {
    {
        let a = arr2(&[[2., 3.], [3., 4.]]);
        let mut df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
        let col = df.select(&["a"], UtahAxis::Column).as_array().unwrap();
        let z = df.append("c", col.view(), UtahAxis::Column).as_df();
        let b = arr2(&[[2., 3., 2.], [3., 3., 4.]]);
        let expected = DataFrame::new(b)
            .columns(&["c", "a", "b"])
            .unwrap();
        assert_eq!(z.unwrap(), expected);
    }
    {
        let a = arr2(&[[2., 3.], [3., 4.]]);
        let mut df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
        let col = df.select(&["1"], UtahAxis::Row).as_array().unwrap();
        let z = df.append("2", col.view(), UtahAxis::Row).as_df();
        let b = arr2(&[[3., 4.], [2., 3.], [3., 4.]]);
        let expected = DataFrame::new(b)
            .columns(&["a", "b"])
            .unwrap()
            .index(&["2", "0", "1"])
            .unwrap();
        assert_eq!(z.unwrap(), expected);
    }
}

#[test]
fn dataframe_mapdf() {
    {
        let a = arr2(&[[2., 3.], [3., 4.]]);
        let mut df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
        let z: Vec<(String, Row<f64>)> = df.map(|x| x * 2.0, UtahAxis::Row).collect();
        let b = arr2(&[[4., 6.], [6., 8.]]);
        let mut expected = Vec::new();
        expected.push(("0".to_string(), b.row(0).to_owned()));
        expected.push(("1".to_string(), b.row(1).to_owned()));
        assert_eq!(z, expected);
    }
    {
        let a = arr2(&[[2., 3.], [3., 4.]]);
        let mut df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
        let z: Vec<(String, Row<f64>)> = df.map(|x| x * 2.0, UtahAxis::Column).collect();
        let b = arr2(&[[4., 6.], [6., 8.]]);
        let mut expected = Vec::new();
        expected.push(("a".to_string(), b.row(0).to_owned()));
        expected.push(("b".to_string(), b.row(1).to_owned()));
        assert_eq!(z, expected);
    }
}

#[test]
fn dataframe_mean() {
    {
        let a = arr2(&[[2., 3.], [3., 4.]]);
        let mut df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
        let z: DataFrame<f64, String> = df.mean(UtahAxis::Row).as_df().unwrap();
        let b = arr2(&[[2.5], [3.5]]);
        let mut expected = DataFrame::new(b).columns(&["a", "b"]).unwrap();
        assert_eq!(z, expected);
    }
    {
        let a = arr2(&[[2., 3.], [3., 4.]]);
        let mut df: DataFrame<f64, String> = DataFrame::new(a).columns(&["a", "b"]).unwrap();
        let z: Vec<(String, Row<f64>)> = df.map(|x| x * 2.0, UtahAxis::Column).collect();
        let b = arr2(&[[4., 6.], [6., 8.]]);
        let mut expected = Vec::new();
        expected.push(("a".to_string(), b.row(0).to_owned()));
        expected.push(("b".to_string(), b.row(1).to_owned()));
        assert_eq!(z, expected);
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::errors::{CompilationError, Error};
use crate::{EvalContext, EvalContextOutputs, EvalOutputs};

/// A higher level interface to EvalContext. A bit closer to a Repl. Provides commands (start with
/// ':') that alter context state or print information.
pub struct CommandContext {
    print_timings: bool,
    eval_context: EvalContext,
    last_errors: Vec<CompilationError>,
}

impl CommandContext {
    pub fn new() -> Result<(CommandContext, EvalContextOutputs), Error> {
        let (eval_context, eval_context_outputs) = EvalContext::new()?;
        let command_context = CommandContext::with_eval_context(eval_context);
        Ok((command_context, eval_context_outputs))
    }

    pub fn with_eval_context(eval_context: EvalContext) -> CommandContext {
        CommandContext {
            print_timings: false,
            eval_context,
            last_errors: Vec::new(),
        }
    }

    pub fn execute(&mut self, to_run: &str) -> Result<EvalOutputs, Error> {
        use regex::Regex;
        use std::time::Instant;
        lazy_static! {
            static ref COMMAND_RE: Regex = Regex::new("^ *(:[^ ]+)( +(.*))?$").unwrap();
        }
        let mut eval_outputs = EvalOutputs::new();
        let start = Instant::now();
        let mut to_eval = Vec::new();
        for line in to_run.lines() {
            // We only accept commands up until the first non-command.
            if to_eval.is_empty() {
                if let Some(captures) = COMMAND_RE.captures(line) {
                    eval_outputs.merge(
                        self.process_command(&captures[1], captures.get(3).map(|m| m.as_str()))?,
                    );
                    continue;
                }
            }
            to_eval.push(line)
        }
        let result = if to_run.is_empty() {
            Ok(EvalOutputs::new())
        } else {
            self.eval_context.eval(&to_eval.join("\n"))
        };
        let duration = start.elapsed();
        match result {
            Ok(m) => {
                eval_outputs.merge(m);
                if self.print_timings {
                    eval_outputs.timing = Some(duration);
                }
                Ok(eval_outputs)
            }
            Err(Error::CompilationErrors(errors)) => {
                self.last_errors = errors.clone();
                Err(Error::CompilationErrors(errors))
            }
            x => x,
        }
    }

    pub fn set_opt_level(&mut self, level: &str) -> Result<(), Error> {
        self.eval_context.set_opt_level(level)
    }

    fn load_config(&mut self) -> Result<EvalOutputs, Error> {
        let mut outputs = EvalOutputs::new();
        if let Some(config_dir) = crate::config_dir() {
            let config_file = config_dir.join("init.evcxr");
            if config_file.exists() {
                println!("Loading startup commands from {:?}", config_file);
                let contents = std::fs::read_to_string(config_file)?;
                for line in contents.lines() {
                    outputs.merge(self.execute(line)?);
                }
            }
            // Note: Loaded *after* init.evcxr so that it can access `:dep`s (or
            // any other state changed by :commands) specified in the init file.
            let prelude_file = config_dir.join("prelude.rs");
            if prelude_file.exists() {
                println!("Executing prelude from {:?}", prelude_file);
                let prelude = std::fs::read_to_string(prelude_file)?;
                outputs.merge(self.execute(&prelude)?);
            }
        }
        Ok(outputs)
    }

    fn process_command(&mut self, command: &str, args: Option<&str>) -> Result<EvalOutputs, Error> {
        match command {
            ":internal_debug" => {
                let debug_mode = !self.eval_context.debug_mode();
                self.eval_context.set_debug_mode(debug_mode);
                text_output(format!("Internals debugging: {}", debug_mode))
            }
            ":load_config" => self.load_config(),
            ":version" => text_output(env!("CARGO_PKG_VERSION")),
            ":vars" => {
                let mut outputs = EvalOutputs::new();
                outputs
                    .content_by_mime_type
                    .insert("text/plain".to_owned(), self.vars_as_text());
                outputs
                    .content_by_mime_type
                    .insert("text/html".to_owned(), self.vars_as_html());
                Ok(outputs)
            }
            ":preserve_vars_on_panic" => {
                self.eval_context.preserve_vars_on_panic = args == Some("1");
                text_output(format!(
                    "Preserve vars on panic: {}",
                    self.eval_context.preserve_vars_on_panic
                ))
            }
            ":clear" => self.eval_context.clear().map(|_| EvalOutputs::new()),
            ":dep" => {
                use regex::Regex;
                let args = if let Some(v) = args {
                    v
                } else {
                    bail!(":dep requires arguments")
                };
                lazy_static! {
                    static ref DEP_RE: Regex = Regex::new("^([^= ]+) *= *(.+)$").unwrap();
                }
                if let Some(captures) = DEP_RE.captures(args) {
                    self.eval_context.add_dep(&captures[1], &captures[2])?;
                    Ok(EvalOutputs::new())
                } else {
                    bail!("Invalid :dep command. Expected: name = ...");
                }
            }
            ":last_compile_dir" => {
                text_output(format!("{:?}", self.eval_context.last_compile_dir()))
            }
            ":opt" => {
                let new_level = if let Some(n) = args {
                    &n
                } else if self.eval_context.opt_level() == "2" {
                    "0"
                } else {
                    "2"
                };
                self.eval_context.set_opt_level(new_level)?;
                text_output(format!("Optimization: {}", self.eval_context.opt_level()))
            }
            ":fmt" => {
                let new_format = if let Some(f) = args { f } else { "{:?}" };
                self.eval_context.set_output_format(new_format.to_owned());
                text_output(format!(
                    "Output format: {}",
                    self.eval_context.output_format()
                ))
            }
            ":timing" => {
                self.print_timings = !self.print_timings;
                text_output(format!("Timing: {}", self.print_timings))
            }
            ":time_passes" => {
                self.eval_context
                    .set_time_passes(!self.eval_context.time_passes());
                text_output(format!("Time passes: {}", self.eval_context.time_passes()))
            }
            ":sccache" => {
                self.eval_context.set_sccache(args != Some("0"))?;
                text_output(format!("sccache: {}", self.eval_context.sccache()))
            }
            ":linker" => {
                if let Some(linker) = args {
                    self.eval_context.set_linker(linker.to_owned());
                }
                text_output(format!("linker: {}", self.eval_context.linker()))
            }
            ":explain" => {
                if self.last_errors.is_empty() {
                    bail!("No last error to explain");
                } else {
                    let mut all_explanations = String::new();
                    for error in &self.last_errors {
                        if let Some(explanation) = error.explanation() {
                            all_explanations.push_str(explanation);
                        } else {
                            bail!("Sorry, last error has no explanation");
                        }
                    }
                    text_output(all_explanations)
                }
            }
            ":last_error_json" => {
                let mut errors_out = String::new();
                for error in &self.last_errors {
                    use std::fmt::Write;
                    write!(&mut errors_out, "{}", error.json)?;
                    errors_out.push('\n');
                }
                bail!(errors_out);
            }
            ":help" => text_output(
                ":vars             List bound variables and their types\n\
                 :opt [level]      Toggle/set optimization level\n\
                 :fmt [format]     Set output formatter (default: {:?}). \n\
                 :explain          Print explanation of last error\n\
                 :clear            Clear all state, keeping compilation cache\n\
                 :dep              Add dependency. e.g. :dep regex = \"1.0\"\n\
                 :sccache [0|1]    Set whether to use sccache.\n\
                 :linker [linker]  Set/print linker. Supported: system, lld\n\
                 :version          Print Evcxr version\n\
                 :preserve_vars_on_panic [0|1]  Try to keep vars on panic\n\n\
                 Mostly for development / debugging purposes:\n\
                 :last_compile_dir Print the directory in which we last compiled\n\
                 :timing           Toggle printing of how long evaluations take\n\
                 :last_error_json  Print the last compilation error as JSON (for debugging)\n\
                 :time_passes      Toggle printing of rustc pass times (requires nightly)\n\
                 :internal_debug   Toggle various internal debugging code",
            ),
            _ => bail!("Unrecognised command {}", command),
        }
    }

    fn vars_as_text(&self) -> String {
        let mut out = String::new();
        for (var, ty) in self.eval_context.variables_and_types() {
            out.push_str(var);
            out.push_str(": ");
            out.push_str(ty);
            out.push_str("\n");
        }
        out
    }

    fn vars_as_html(&self) -> String {
        let mut out = String::new();
        out.push_str("

Variable	Type
");
        for (var, ty) in self.eval_context.variables_and_types() {
            out.push_str("
");
            html_escape(var, &mut out);
            out.push_str("	");
            html_escape(ty, &mut out);
            out.push_str("
");
        }
        out.push_str("
");
        out
    }
}

fn html_escape(input: &str, out: &mut String) {
    for ch in input.chars() {
        match ch {
            '<' => out.push_str("<"),
            '>' => out.push_str(">"),
            x => out.push(x),
        }
    }
}

fn text_output<T: Into<String>>(text: T) -> Result<EvalOutputs, Error> {
    let mut outputs = EvalOutputs::new();
    let mut content = text.into();
    content.push('\n');
    outputs
        .content_by_mime_type
        .insert("text/plain".to_owned(), content);
    Ok(outputs)
}
<commit_msg>Treat :dep name the same as :dep name = "*". Fixes #97<commit_after>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::errors::{CompilationError, Error};
use crate::{EvalContext, EvalContextOutputs, EvalOutputs};

/// A higher level interface to EvalContext. A bit closer to a Repl. Provides commands (start with
/// ':') that alter context state or print information.
pub struct CommandContext {
    print_timings: bool,
    eval_context: EvalContext,
    last_errors: Vec<CompilationError>,
}

impl CommandContext {
    pub fn new() -> Result<(CommandContext, EvalContextOutputs), Error> {
        let (eval_context, eval_context_outputs) = EvalContext::new()?;
        let command_context = CommandContext::with_eval_context(eval_context);
        Ok((command_context, eval_context_outputs))
    }

    pub fn with_eval_context(eval_context: EvalContext) -> CommandContext {
        CommandContext {
            print_timings: false,
            eval_context,
            last_errors: Vec::new(),
        }
    }

    pub fn execute(&mut self, to_run: &str) -> Result<EvalOutputs, Error> {
        use regex::Regex;
        use std::time::Instant;
        lazy_static! {
            static ref COMMAND_RE: Regex = Regex::new("^ *(:[^ ]+)( +(.*))?$").unwrap();
        }
        let mut eval_outputs = EvalOutputs::new();
        let start = Instant::now();
        let mut to_eval = Vec::new();
        for line in to_run.lines() {
            // We only accept commands up until the first non-command.
            if to_eval.is_empty() {
                if let Some(captures) = COMMAND_RE.captures(line) {
                    eval_outputs.merge(
                        self.process_command(&captures[1], captures.get(3).map(|m| m.as_str()))?,
                    );
                    continue;
                }
            }
            to_eval.push(line)
        }
        let result = if to_run.is_empty() {
            Ok(EvalOutputs::new())
        } else {
            self.eval_context.eval(&to_eval.join("\n"))
        };
        let duration = start.elapsed();
        match result {
            Ok(m) => {
                eval_outputs.merge(m);
                if self.print_timings {
                    eval_outputs.timing = Some(duration);
                }
                Ok(eval_outputs)
            }
            Err(Error::CompilationErrors(errors)) => {
                self.last_errors = errors.clone();
                Err(Error::CompilationErrors(errors))
            }
            x => x,
        }
    }

    pub fn set_opt_level(&mut self, level: &str) -> Result<(), Error> {
        self.eval_context.set_opt_level(level)
    }

    fn load_config(&mut self) -> Result<EvalOutputs, Error> {
        let mut outputs = EvalOutputs::new();
        if let Some(config_dir) = crate::config_dir() {
            let config_file = config_dir.join("init.evcxr");
            if config_file.exists() {
                println!("Loading startup commands from {:?}", config_file);
                let contents = std::fs::read_to_string(config_file)?;
                for line in contents.lines() {
                    outputs.merge(self.execute(line)?);
                }
            }
            // Note: Loaded *after* init.evcxr so that it can access `:dep`s (or
            // any other state changed by :commands) specified in the init file.
            let prelude_file = config_dir.join("prelude.rs");
            if prelude_file.exists() {
                println!("Executing prelude from {:?}", prelude_file);
                let prelude = std::fs::read_to_string(prelude_file)?;
                outputs.merge(self.execute(&prelude)?);
            }
        }
        Ok(outputs)
    }

    fn process_command(&mut self, command: &str, args: Option<&str>) -> Result<EvalOutputs, Error> {
        match command {
            ":internal_debug" => {
                let debug_mode = !self.eval_context.debug_mode();
                self.eval_context.set_debug_mode(debug_mode);
                text_output(format!("Internals debugging: {}", debug_mode))
            }
            ":load_config" => self.load_config(),
            ":version" => text_output(env!("CARGO_PKG_VERSION")),
            ":vars" => {
                let mut outputs = EvalOutputs::new();
                outputs
                    .content_by_mime_type
                    .insert("text/plain".to_owned(), self.vars_as_text());
                outputs
                    .content_by_mime_type
                    .insert("text/html".to_owned(), self.vars_as_html());
                Ok(outputs)
            }
            ":preserve_vars_on_panic" => {
                self.eval_context.preserve_vars_on_panic = args == Some("1");
                text_output(format!(
                    "Preserve vars on panic: {}",
                    self.eval_context.preserve_vars_on_panic
                ))
            }
            ":clear" => self.eval_context.clear().map(|_| EvalOutputs::new()),
            ":dep" => {
                use regex::Regex;
                let args = if let Some(v) = args {
                    v
                } else {
                    bail!(":dep requires arguments")
                };
                lazy_static! {
                    static ref DEP_RE: Regex = Regex::new("^([^= ]+) *(= *(.+))?$").unwrap();
                }
                if let Some(captures) = DEP_RE.captures(args) {
                    self.eval_context.add_dep(
                        &captures[1],
                        &captures.get(3).map_or("\"*\"", |m| m.as_str()),
                    )?;
                    Ok(EvalOutputs::new())
                } else {
                    bail!("Invalid :dep command. Expected: name = ... or just name");
                }
            }
            ":last_compile_dir" => {
                text_output(format!("{:?}", self.eval_context.last_compile_dir()))
            }
            ":opt" => {
                let new_level = if let Some(n) = args {
                    &n
                } else if self.eval_context.opt_level() == "2" {
                    "0"
                } else {
                    "2"
                };
                self.eval_context.set_opt_level(new_level)?;
                text_output(format!("Optimization: {}", self.eval_context.opt_level()))
            }
            ":fmt" => {
                let new_format = if let Some(f) = args { f } else { "{:?}" };
                self.eval_context.set_output_format(new_format.to_owned());
                text_output(format!(
                    "Output format: {}",
                    self.eval_context.output_format()
                ))
            }
            ":timing" => {
                self.print_timings = !self.print_timings;
                text_output(format!("Timing: {}", self.print_timings))
            }
            ":time_passes" => {
                self.eval_context
                    .set_time_passes(!self.eval_context.time_passes());
                text_output(format!("Time passes: {}", self.eval_context.time_passes()))
            }
            ":sccache" => {
                self.eval_context.set_sccache(args != Some("0"))?;
                text_output(format!("sccache: {}", self.eval_context.sccache()))
            }
            ":linker" => {
                if let Some(linker) = args {
                    self.eval_context.set_linker(linker.to_owned());
                }
                text_output(format!("linker: {}", self.eval_context.linker()))
            }
            ":explain" => {
                if self.last_errors.is_empty() {
                    bail!("No last error to explain");
                } else {
                    let mut all_explanations = String::new();
                    for error in &self.last_errors {
                        if let Some(explanation) = error.explanation() {
                            all_explanations.push_str(explanation);
                        } else {
                            bail!("Sorry, last error has no explanation");
                        }
                    }
                    text_output(all_explanations)
                }
            }
            ":last_error_json" => {
                let mut errors_out = String::new();
                for error in &self.last_errors {
                    use std::fmt::Write;
                    write!(&mut errors_out, "{}", error.json)?;
                    errors_out.push('\n');
                }
                bail!(errors_out);
            }
            ":help" => text_output(
                ":vars             List bound variables and their types\n\
                 :opt [level]      Toggle/set optimization level\n\
                 :fmt [format]     Set output formatter (default: {:?}). \n\
                 :explain          Print explanation of last error\n\
                 :clear            Clear all state, keeping compilation cache\n\
                 :dep              Add dependency. e.g. :dep regex = \"1.0\"\n\
                 :sccache [0|1]    Set whether to use sccache.\n\
                 :linker [linker]  Set/print linker. Supported: system, lld\n\
                 :version          Print Evcxr version\n\
                 :preserve_vars_on_panic [0|1]  Try to keep vars on panic\n\n\
                 Mostly for development / debugging purposes:\n\
                 :last_compile_dir Print the directory in which we last compiled\n\
                 :timing           Toggle printing of how long evaluations take\n\
                 :last_error_json  Print the last compilation error as JSON (for debugging)\n\
                 :time_passes      Toggle printing of rustc pass times (requires nightly)\n\
                 :internal_debug   Toggle various internal debugging code",
            ),
            _ => bail!("Unrecognised command {}", command),
        }
    }

    fn vars_as_text(&self) -> String {
        let mut out = String::new();
        for (var, ty) in self.eval_context.variables_and_types() {
            out.push_str(var);
            out.push_str(": ");
            out.push_str(ty);
            out.push_str("\n");
        }
        out
    }

    fn vars_as_html(&self) -> String {
        let mut out = String::new();
        out.push_str("

Variable	Type
");
        for (var, ty) in self.eval_context.variables_and_types() {
            out.push_str("
");
            html_escape(var, &mut out);
            out.push_str("	");
            html_escape(ty, &mut out);
            out.push_str("
");
        }
        out.push_str("
");
        out
    }
}

fn html_escape(input: &str, out: &mut String) {
    for ch in input.chars() {
        match ch {
            '<' => out.push_str("<"),
            '>' => out.push_str(">"),
            x => out.push(x),
        }
    }
}

fn text_output<T: Into<String>>(text: T) -> Result<EvalOutputs, Error> {
    let mut outputs = EvalOutputs::new();
    let mut content = text.into();
    content.push('\n');
    outputs
        .content_by_mime_type
        .insert("text/plain".to_owned(), content);
    Ok(outputs)
}
<|endoftext|>


<commit_before>//extern mod oxidize;

extern mod http;

//use oxidize::Oxidize;
//use oxidize::Request;
//use oxidize::Response;
//use oxidize::render;
//use oxidize::Router;
use std::hashmap::HashMap;
use http::status;
use http::status::Status;

/////////////////////////
// These are functions that I want Oxidize to define
// I'm just putting them in here for now
/////////////////////////

//enum Method {
//	GET,
//	POST,
//	WS
//}

pub struct User {
	id : uint,
	is_anonymous : bool,
	is_authenticated : bool,
	is_superuser : bool,
}

pub struct Request {
	method : ~str, //Method,
    GET : HashMap<~str, ~str>,
    POST : HashMap<~str, ~str>,
}

pub struct Response {
	content : ~str,
	status: Status
	// add more stuff? I dunno
	//reason_phrase : ~str,
	//streaming : bool,
}

impl Response {
	fn new(status : Status, content : ~str) -> Response {
		Response { content: content, status: status}
	}
}

// todo: Make the context vars better
fn render(request : Request, template : &str, context : Option<HashMap<&str, &str>>) -> ~str {
	// load the template file and run it through the parser
	~"NOTHING HAHAHAHAHA"
}

type Route<'a> = (&'a str, &'a str, fn(Request) -> Response);

//////////////////////////
// This is what I want the example to look like
//////////////////////////

static routes: &'static [Route<'static>] = &[
	("GET", "/", index),
	("GET", "/test", index)
];

pub fn index(request: Request) -> Response {
	return Response::new(status::Ok, render(request, "templates/index.html", None));
}

fn main() {
	//let server = Oxidize::new(8000);
	//server.serve_forever();
}<commit_msg>Changing to two spaces instead of tabs.<commit_after>//extern mod oxidize;

extern mod http;

//use oxidize::Oxidize;
//use oxidize::Request;
//use oxidize::Response;
//use oxidize::render;
//use oxidize::Router;
use std::hashmap::HashMap;
use http::status;
use http::status::Status;

/////////////////////////
// These are functions that I want Oxidize to define
// I'm just putting them in here for now
/////////////////////////

//enum Method {
//  GET,
//  POST,
//  WS
//}

pub struct User {
  id : uint,
  is_anonymous : bool,
  is_authenticated : bool,
  is_superuser : bool,
}

pub struct Request {
  method : ~str, //Method,
  GET : HashMap<~str, ~str>,
  POST : HashMap<~str, ~str>,
}

pub struct Response {
  content : ~str,
  status: Status
  // add more stuff? I dunno
  //reason_phrase : ~str,
  //streaming : bool,
}

impl Response {
  fn new(status : Status, content : ~str) -> Response {
    Response { content: content, status: status}
  }
}

// todo: Make the context vars better
fn render(request : Request, template : &str, context : Option<HashMap<&str, &str>>) -> ~str {
  // load the template file and run it through the parser
  ~"NOTHING HAHAHAHAHA"
}

type Route<'a> = (&'a str, &'a str, fn(Request) -> Response);

//////////////////////////
// This is what I want the example to look like
//////////////////////////

static routes: &'static [Route<'static>] = &[
  ("GET", "/", index),
  ("GET", "/test", index)
];

pub fn index(request: Request) -> Response {
  return Response::new(status::Ok, render(request, "templates/index.html", None));
}

fn main() {
  //let server = Oxidize::new(8000);
  //server.serve_forever();
}<|endoftext|>