<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
//
//      http://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::proto;
use crate::proto_grpc;
use cgmath::{Decomposed, Matrix4, PerspectiveFov, Point3, Quaternion, Rad, Transform, Vector3};
use collision::Aabb3;
use futures::sync::mpsc;
use futures::{Future, Sink, Stream};
use grpcio::{
    Environment, RpcContext, RpcStatus, RpcStatusCode, Server, ServerBuilder, ServerStreamingSink,
    UnarySink, WriteFlags,
};
use point_viewer::errors::*;
use point_viewer::octree::{NodeId, Octree, OctreeFactory};
use point_viewer::{InternalIterator, Point};
use protobuf::Message;
use std::collections::HashMap;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::{Arc, RwLock};

struct OctreeServiceData {
    octree: Box<Octree>,
    meta: point_viewer::proto::Meta,
}

#[derive(Clone)]
struct OctreeService {
    location: PathBuf,
    data_cache: Arc<RwLock<HashMap<String, Arc<OctreeServiceData>>>>,
    factory: OctreeFactory,
}

#[derive(Debug)]
enum OctreeQuery {
    Frustum(Matrix4<f32>),
    Box(Aabb3<f64>),
    FullPointcloud,
}

fn send_fail_stream<T>(ctx: &RpcContext, sink: ServerStreamingSink<T>, err_str: String) {
    let f = sink
        .fail(RpcStatus::new(RpcStatusCode::Internal, Some(err_str)))
        .map_err(move |err| eprintln!("Failed to reply: {:?}", err));
    ctx.spawn(f);
}

fn send_fail<T>(ctx: &RpcContext, sink: UnarySink<T>, err_str: String) {
    let f = sink
        .fail(RpcStatus::new(RpcStatusCode::Internal, Some(err_str)))
        .map_err(move |err| eprintln!("Failed to reply: {:?}", err));
    ctx.spawn(f);
}

impl proto_grpc::Octree for OctreeService {
    fn get_meta(
        &self,
        ctx: RpcContext,
        req: proto::GetMetaRequest,
        sink: UnarySink<proto::GetMetaReply>,
    ) {
        let mut resp = proto::GetMetaReply::new();
        let service_data = match self.get_service_data(&req.octree_id) {
            Ok(service_data) => service_data,
            Err(e) => return send_fail(&ctx, sink, e.to_string()),
        };
        resp.set_meta(service_data.meta.clone());
        let f = sink
            .success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_node_data(
        &self,
        ctx: RpcContext,
        req: proto::GetNodeDataRequest,
        sink: UnarySink<proto::GetNodeDataReply>,
    ) {
        let service_data = match self.get_service_data(&req.octree_id) {
            Ok(service_data) => service_data,
            Err(e) => return send_fail(&ctx, sink, e.to_string()),
        };
        let node_id = match NodeId::from_str(&req.id) {
            Ok(node_id) => node_id,
            Err(e) => return send_fail(&ctx, sink, e.to_string()),
        };
        let node_data = match service_data.octree.get_node_data(&node_id) {
            Ok(data) => data,
            Err(e) => return send_fail(&ctx, sink, e.to_string()),
        };
        let mut resp = proto::GetNodeDataReply::new();
        resp.mut_node()
            .set_position_encoding(node_data.meta.position_encoding.to_proto());
        resp.mut_node().set_num_points(node_data.meta.num_points);
        resp.set_position(node_data.position);
        resp.set_color(node_data.color);
        let f = sink
            .success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_points_in_frustum(
        &self,
        ctx: RpcContext,
        req: proto::GetPointsInFrustumRequest,
        resp: ServerStreamingSink<proto::PointsReply>,
    ) {
        let projection_matrix = Matrix4::from(PerspectiveFov {
            fovy: Rad(req.fovy_rad as f32),
            aspect: (req.aspect as f32),
            near: (req.z_near as f32),
            far: (req.z_far as f32),
        });
        let rotation = {
            let q = req.rotation.unwrap();
            Quaternion::new(q.w, q.x, q.y, q.z)
        };

        let translation = {
            let t = req.translation.unwrap();
            Vector3::new(t.x, t.y, t.z)
        };

        let view_transform = Decomposed {
            scale: 1.0,
            rot: rotation,
            disp: translation,
        };
        let frustum_matrix = projection_matrix.concat(&view_transform.into());
        self.stream_points_back_to_sink(
            OctreeQuery::Frustum(frustum_matrix),
            &req.octree_id,
            &ctx,
            resp,
        )
    }

    fn get_points_in_box(
        &self,
        ctx: RpcContext,
        req: proto::GetPointsInBoxRequest,
        resp: ServerStreamingSink<proto::PointsReply>,
    ) {
        let bounding_box = {
            let bounding_box = req.bounding_box.clone().unwrap();
            let min = bounding_box.min.unwrap();
            let max = bounding_box.max.unwrap();
            Aabb3::new(
                Point3::new(min.x, min.y, min.z),
                Point3::new(max.x, max.y, max.z),
            )
        };
        self.stream_points_back_to_sink(OctreeQuery::Box(bounding_box), &req.octree_id, &ctx, resp)
    }

    fn get_all_points(
        &self,
        ctx: RpcContext,
        req: proto::GetAllPointsRequest,
        resp: ServerStreamingSink<proto::PointsReply>,
    ) {
        self.stream_points_back_to_sink(OctreeQuery::FullPointcloud, &req.octree_id, &ctx, resp)
    }
}

impl OctreeService {
    fn stream_points_back_to_sink(
        &self,
        query: OctreeQuery,
        octree_id: &str,
        ctx: &RpcContext,
        resp: ServerStreamingSink<proto::PointsReply>,
    ) {
        use std::thread;

        let service_data = match self.get_service_data(octree_id) {
            Ok(service_data) => service_data,
            Err(e) => return send_fail_stream(&ctx, resp, e.to_string()),
        };

        // This creates a async-aware (tx, rx) pair that can wake up the event loop when new data
        // is piped through it.

        // We create a channel with a small buffer, which yields better performance than
        // fully blocking without requiring a ton of memory. This has not been carefully benchmarked
        // for best performance though.
        let (tx, rx) = mpsc::channel(4);
        thread::spawn(move || {
            // This is the secret sauce connecting an OS thread to a event-based receiver. Calling
            // wait() on this turns the event aware, i.e. async 'tx' into a blocking 'tx' that will
            // make this thread block when the event loop is not quick enough with piping out data.
            let mut tx = tx.wait();

            let mut reply = proto::PointsReply::new();
            let bytes_per_point = {
                let initial_proto_size = reply.compute_size();
                let mut v = point_viewer::proto::Vector3d::new();
                v.set_x(1.);
                v.set_y(1.);
                v.set_z(1.);
                reply.mut_positions().push(v);

                let mut v = point_viewer::proto::Color::new();
                v.set_red(1.);
                v.set_green(1.);
                v.set_blue(1.);
                v.set_alpha(1.);
                reply.mut_colors().push(v);

                reply.mut_intensities().push(1.);

                let final_proto_size = reply.compute_size();
                reply.mut_positions().clear();
                reply.mut_colors().clear();
                reply.mut_intensities().clear();
                final_proto_size - initial_proto_size
            };

            // Proto message must be below 4 MB.
            let max_message_size = 4 * 1024 * 1024;
            let mut reply_size = 0;

            {
                // Extra scope to make sure that 'func' does not outlive 'reply'.
                let func = |p: &Point| {
                    {
                        let mut v = point_viewer::proto::Vector3d::new();
                        v.set_x(p.position.x);
                        v.set_y(p.position.y);
                        v.set_z(p.position.z);
                        reply.mut_positions().push(v);
                    }

                    {
                        let mut v = point_viewer::proto::Color::new();
                        let clr = p.color.to_f32();
                        v.set_red(clr.red);
                        v.set_green(clr.green);
                        v.set_blue(clr.blue);
                        v.set_alpha(clr.alpha);
                        reply.mut_colors().push(v);
                    }

                    if let Some(i) = p.intensity {
                        reply.mut_intensities().push(i);
                    }

                    reply_size += bytes_per_point;
                    if reply_size > max_message_size - bytes_per_point {
                        tx.send((reply.clone(), WriteFlags::default())).unwrap();
                        reply.mut_positions().clear();
                        reply.mut_colors().clear();
                        reply.mut_intensities().clear();
                        reply_size = 0;
                    }
                };
                match query {
                    OctreeQuery::Box(bounding_box) => service_data
                        .octree
                        .points_in_box(&bounding_box)
                        .for_each(func),
                    OctreeQuery::Frustum(frustum_matrix) => service_data
                        .octree
                        .points_in_frustum(&frustum_matrix)
                        .for_each(func),
                    OctreeQuery::FullPointcloud => service_data.octree.all_points().for_each(func),
                };
            }
            tx.send((reply, WriteFlags::default())).unwrap();
        });

        let rx = rx.map_err(|_| grpcio::Error::RemoteStopped);
        let f = resp
            .send_all(rx)
            .map(|_| {})
            .map_err(|e| println!("failed to reply: {:?}", e));
        ctx.spawn(f)
    }

    fn get_service_data(&self, octree_id: &str) -> Result<Arc<OctreeServiceData>> {
        match self.data_cache.read().unwrap().get(octree_id) {
            None => {
                let octree = self
                    .factory
                    .generate_octree(self.location.join(&octree_id).to_string_lossy())?;
                let meta = octree.to_meta_proto();
                let service_data = Arc::new(OctreeServiceData { octree, meta });
                self.data_cache
                    .write()
                    .unwrap()
                    .insert(octree_id.to_string(), Arc::clone(&service_data));
                Ok(service_data)
            }
            Some(service_data) => Ok(Arc::clone(service_data)),
        }
    }
}

pub fn start_grpc_server(
    host: &str,
    port: u16,
    location: impl Into<PathBuf>,
    factory: OctreeFactory,
) -> Server {
    let env = Arc::new(Environment::new(1));
    let data_cache = Arc::new(RwLock::new(HashMap::new()));

    let service = proto_grpc::create_octree(OctreeService {
        location: location.into(),
        data_cache,
        factory,
    });
    ServerBuilder::new(env)
        .register_service(service)
        .bind(host /* ip to bind to */, port)
        .build()
        .unwrap()
}
<commit_msg>Fixes grpc server starving. (#238)<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
//
//      http://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::proto;
use crate::proto_grpc;
use cgmath::{Decomposed, Matrix4, PerspectiveFov, Point3, Quaternion, Rad, Transform, Vector3};
use collision::Aabb3;
use futures::sync::mpsc;
use futures::{Future, Sink, Stream};
use grpcio::{
    Environment, RpcContext, RpcStatus, RpcStatusCode, Server, ServerBuilder, ServerStreamingSink,
    UnarySink, WriteFlags,
};
use point_viewer::errors::*;
use point_viewer::octree::{NodeId, Octree, OctreeFactory};
use point_viewer::{InternalIterator, Point};
use protobuf::Message;
use std::collections::HashMap;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::{Arc, RwLock};

struct OctreeServiceData {
    octree: Box<Octree>,
    meta: point_viewer::proto::Meta,
}

#[derive(Clone)]
struct OctreeService {
    location: PathBuf,
    data_cache: Arc<RwLock<HashMap<String, Arc<OctreeServiceData>>>>,
    factory: OctreeFactory,
}

#[derive(Debug)]
enum OctreeQuery {
    Frustum(Matrix4<f32>),
    Box(Aabb3<f64>),
    FullPointcloud,
}

fn send_fail_stream<T>(ctx: &RpcContext, sink: ServerStreamingSink<T>, err_str: String) {
    let f = sink
        .fail(RpcStatus::new(RpcStatusCode::Internal, Some(err_str)))
        .map_err(move |err| eprintln!("Failed to reply: {:?}", err));
    ctx.spawn(f);
}

fn send_fail<T>(ctx: &RpcContext, sink: UnarySink<T>, err_str: String) {
    let f = sink
        .fail(RpcStatus::new(RpcStatusCode::Internal, Some(err_str)))
        .map_err(move |err| eprintln!("Failed to reply: {:?}", err));
    ctx.spawn(f);
}

impl proto_grpc::Octree for OctreeService {
    fn get_meta(
        &self,
        ctx: RpcContext,
        req: proto::GetMetaRequest,
        sink: UnarySink<proto::GetMetaReply>,
    ) {
        let mut resp = proto::GetMetaReply::new();
        let service_data = match self.get_service_data(&req.octree_id) {
            Ok(service_data) => service_data,
            Err(e) => return send_fail(&ctx, sink, e.to_string()),
        };
        resp.set_meta(service_data.meta.clone());
        let f = sink
            .success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_node_data(
        &self,
        ctx: RpcContext,
        req: proto::GetNodeDataRequest,
        sink: UnarySink<proto::GetNodeDataReply>,
    ) {
        let service_data = match self.get_service_data(&req.octree_id) {
            Ok(service_data) => service_data,
            Err(e) => return send_fail(&ctx, sink, e.to_string()),
        };
        let node_id = match NodeId::from_str(&req.id) {
            Ok(node_id) => node_id,
            Err(e) => return send_fail(&ctx, sink, e.to_string()),
        };
        let node_data = match service_data.octree.get_node_data(&node_id) {
            Ok(data) => data,
            Err(e) => return send_fail(&ctx, sink, e.to_string()),
        };
        let mut resp = proto::GetNodeDataReply::new();
        resp.mut_node()
            .set_position_encoding(node_data.meta.position_encoding.to_proto());
        resp.mut_node().set_num_points(node_data.meta.num_points);
        resp.set_position(node_data.position);
        resp.set_color(node_data.color);
        let f = sink
            .success(resp)
            .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
        ctx.spawn(f)
    }

    fn get_points_in_frustum(
        &self,
        ctx: RpcContext,
        req: proto::GetPointsInFrustumRequest,
        resp: ServerStreamingSink<proto::PointsReply>,
    ) {
        let projection_matrix = Matrix4::from(PerspectiveFov {
            fovy: Rad(req.fovy_rad as f32),
            aspect: (req.aspect as f32),
            near: (req.z_near as f32),
            far: (req.z_far as f32),
        });
        let rotation = {
            let q = req.rotation.unwrap();
            Quaternion::new(q.w, q.x, q.y, q.z)
        };

        let translation = {
            let t = req.translation.unwrap();
            Vector3::new(t.x, t.y, t.z)
        };

        let view_transform = Decomposed {
            scale: 1.0,
            rot: rotation,
            disp: translation,
        };
        let frustum_matrix = projection_matrix.concat(&view_transform.into());
        self.stream_points_back_to_sink(
            OctreeQuery::Frustum(frustum_matrix),
            &req.octree_id,
            &ctx,
            resp,
        )
    }

    fn get_points_in_box(
        &self,
        ctx: RpcContext,
        req: proto::GetPointsInBoxRequest,
        resp: ServerStreamingSink<proto::PointsReply>,
    ) {
        let bounding_box = {
            let bounding_box = req.bounding_box.clone().unwrap();
            let min = bounding_box.min.unwrap();
            let max = bounding_box.max.unwrap();
            Aabb3::new(
                Point3::new(min.x, min.y, min.z),
                Point3::new(max.x, max.y, max.z),
            )
        };
        self.stream_points_back_to_sink(OctreeQuery::Box(bounding_box), &req.octree_id, &ctx, resp)
    }

    fn get_all_points(
        &self,
        ctx: RpcContext,
        req: proto::GetAllPointsRequest,
        resp: ServerStreamingSink<proto::PointsReply>,
    ) {
        self.stream_points_back_to_sink(OctreeQuery::FullPointcloud, &req.octree_id, &ctx, resp)
    }
}

impl OctreeService {
    fn stream_points_back_to_sink(
        &self,
        query: OctreeQuery,
        octree_id: &str,
        ctx: &RpcContext,
        resp: ServerStreamingSink<proto::PointsReply>,
    ) {
        use std::thread;

        let service_data = match self.get_service_data(octree_id) {
            Ok(service_data) => service_data,
            Err(e) => return send_fail_stream(&ctx, resp, e.to_string()),
        };

        // This creates a async-aware (tx, rx) pair that can wake up the event loop when new data
        // is piped through it.

        // We create a channel with a small buffer, which yields better performance than
        // fully blocking without requiring a ton of memory. This has not been carefully benchmarked
        // for best performance though.
        let (tx, rx) = mpsc::channel(4);
        thread::spawn(move || {
            // This is the secret sauce connecting an OS thread to a event-based receiver. Calling
            // wait() on this turns the event aware, i.e. async 'tx' into a blocking 'tx' that will
            // make this thread block when the event loop is not quick enough with piping out data.
            let mut tx = tx.wait();

            let mut reply = proto::PointsReply::new();
            let bytes_per_point = {
                let initial_proto_size = reply.compute_size();
                let mut v = point_viewer::proto::Vector3d::new();
                v.set_x(1.);
                v.set_y(1.);
                v.set_z(1.);
                reply.mut_positions().push(v);

                let mut v = point_viewer::proto::Color::new();
                v.set_red(1.);
                v.set_green(1.);
                v.set_blue(1.);
                v.set_alpha(1.);
                reply.mut_colors().push(v);

                reply.mut_intensities().push(1.);

                let final_proto_size = reply.compute_size();
                reply.mut_positions().clear();
                reply.mut_colors().clear();
                reply.mut_intensities().clear();
                final_proto_size - initial_proto_size
            };

            // Proto message must be below 4 MB.
            let max_message_size = 4 * 1024 * 1024;
            let mut reply_size = 0;

            {
                // Extra scope to make sure that 'func' does not outlive 'reply'.
                let func = |p: &Point| {
                    {
                        let mut v = point_viewer::proto::Vector3d::new();
                        v.set_x(p.position.x);
                        v.set_y(p.position.y);
                        v.set_z(p.position.z);
                        reply.mut_positions().push(v);
                    }

                    {
                        let mut v = point_viewer::proto::Color::new();
                        let clr = p.color.to_f32();
                        v.set_red(clr.red);
                        v.set_green(clr.green);
                        v.set_blue(clr.blue);
                        v.set_alpha(clr.alpha);
                        reply.mut_colors().push(v);
                    }

                    if let Some(i) = p.intensity {
                        reply.mut_intensities().push(i);
                    }

                    reply_size += bytes_per_point;
                    if reply_size > max_message_size - bytes_per_point {
                        tx.send((reply.clone(), WriteFlags::default())).unwrap();
                        reply.mut_positions().clear();
                        reply.mut_colors().clear();
                        reply.mut_intensities().clear();
                        reply_size = 0;
                    }
                };
                match query {
                    OctreeQuery::Box(bounding_box) => service_data
                        .octree
                        .points_in_box(&bounding_box)
                        .for_each(func),
                    OctreeQuery::Frustum(frustum_matrix) => service_data
                        .octree
                        .points_in_frustum(&frustum_matrix)
                        .for_each(func),
                    OctreeQuery::FullPointcloud => service_data.octree.all_points().for_each(func),
                };
            }
            tx.send((reply, WriteFlags::default())).unwrap();
        });

        let rx = rx.map_err(|_| grpcio::Error::RemoteStopped);
        let f = resp
            .send_all(rx)
            .map(|_| {})
            .map_err(|e| println!("failed to reply: {:?}", e));
        ctx.spawn(f)
    }

    fn get_service_data(&self, octree_id: &str) -> Result<Arc<OctreeServiceData>> {
        let read_cache = self.data_cache.read().unwrap();
        match read_cache.get(octree_id) {
            None => {
                drop(read_cache);
                let octree = self
                    .factory
                    .generate_octree(self.location.join(&octree_id).to_string_lossy())?;
                let meta = octree.to_meta_proto();
                let service_data = Arc::new(OctreeServiceData { octree, meta });
                self.data_cache
                    .write()
                    .unwrap()
                    .insert(octree_id.to_string(), Arc::clone(&service_data));
                Ok(service_data)
            }
            Some(service_data) => Ok(Arc::clone(service_data)),
        }
    }
}

pub fn start_grpc_server(
    host: &str,
    port: u16,
    location: impl Into<PathBuf>,
    factory: OctreeFactory,
) -> Server {
    let env = Arc::new(Environment::new(1));
    let data_cache = Arc::new(RwLock::new(HashMap::new()));

    let service = proto_grpc::create_octree(OctreeService {
        location: location.into(),
        data_cache,
        factory,
    });
    ServerBuilder::new(env)
        .register_service(service)
        .bind(host /* ip to bind to */, port)
        .build()
        .unwrap()
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::{mem, result};

use gdt;
use kvm;
use kvm_sys::kvm_fpu;
use kvm_sys::kvm_msr_entry;
use kvm_sys::kvm_msrs;
use kvm_sys::kvm_regs;
use kvm_sys::kvm_sregs;
use layout;
use memory_model::{GuestAddress, GuestMemory};
use sys_util;

#[derive(Debug)]
pub enum Error {
    /// Setting up msrs failed.
    MsrIoctlFailed(sys_util::Error),
    /// Failed to configure the FPU.
    FpuIoctlFailed(sys_util::Error),
    /// Failed to set base registers for this cpu.
    SettingRegistersIoctl(sys_util::Error),
    /// Failed to set sregs for this cpu.
    SRegsIoctlFailed(sys_util::Error),
    /// Writing the GDT to RAM failed.
    WriteGDTFailure,
    /// Writing the IDT to RAM failed.
    WriteIDTFailure,
    /// Writing PML4 to RAM failed.
    WritePML4Address,
    /// Writing PDPTE to RAM failed.
    WritePDPTEAddress,
}
pub type Result<T> = result::Result<T, Error>;

fn create_msr_entries() -> Vec<kvm_msr_entry> {
    let mut entries = Vec::<kvm_msr_entry>::new();

    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_IA32_SYSENTER_CS,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_IA32_SYSENTER_ESP,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_IA32_SYSENTER_EIP,
        data: 0x0,
        ..Default::default()
    });
    // x86_64 specific msrs, we only run on x86_64 not x86
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_STAR,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_CSTAR,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_KERNEL_GS_BASE,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_SYSCALL_MASK,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_LSTAR,
        data: 0x0,
        ..Default::default()
    });
    // end of x86_64 specific code
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_IA32_TSC,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_IA32_MISC_ENABLE,
        data: ::msr_index::MSR_IA32_MISC_ENABLE_FAST_STRING as u64,
        ..Default::default()
    });

    entries
}

/// Configure Model specific registers for x86
///
/// # Arguments
///
/// * `vcpu` - Structure for the vcpu that holds the vcpu fd.
pub fn setup_msrs(vcpu: &kvm::VcpuFd) -> Result<()> {
    let entry_vec = create_msr_entries();
    let vec_size_bytes =
        mem::size_of::<kvm_msrs>() + (entry_vec.len() * mem::size_of::<kvm_msr_entry>());
    let vec: Vec<u8> = Vec::with_capacity(vec_size_bytes);
    let msrs: &mut kvm_msrs = unsafe {
        // Converting the vector's memory to a struct is unsafe.  Carefully using the read-only
        // vector to size and set the members ensures no out-of-bounds erros below.
        &mut *(vec.as_ptr() as *mut kvm_msrs)
    };

    unsafe {
        // Mapping the unsized array to a slice is unsafe becase the length isn't known.  Providing
        // the length used to create the struct guarantees the entire slice is valid.
        let entries: &mut [kvm_msr_entry] = msrs.entries.as_mut_slice(entry_vec.len());
        entries.copy_from_slice(&entry_vec);
    }
    msrs.nmsrs = entry_vec.len() as u32;

    vcpu.set_msrs(msrs).map_err(Error::MsrIoctlFailed)?;

    Ok(())
}

/// Configure FPU registers for x86
///
/// # Arguments
///
/// * `vcpu` - Structure for the vcpu that holds the vcpu fd.
pub fn setup_fpu(vcpu: &kvm::VcpuFd) -> Result<()> {
    let fpu: kvm_fpu = kvm_fpu {
        fcw: 0x37f,
        mxcsr: 0x1f80,
        ..Default::default()
    };

    vcpu.set_fpu(&fpu).map_err(Error::FpuIoctlFailed)?;

    Ok(())
}

/// Configure base registers for x86
///
/// # Arguments
///
/// * `vcpu` - Structure for the vcpu that holds the vcpu fd.
/// * `boot_ip` - Starting instruction pointer.
/// * `boot_sp` - Starting stack pointer.
/// * `boot_si` - Must point to zero page address per Linux ABI.
pub fn setup_regs(vcpu: &kvm::VcpuFd, boot_ip: u64, boot_sp: u64, boot_si: u64) -> Result<()> {
    let regs: kvm_regs = kvm_regs {
        rflags: 0x0000000000000002u64,
        rip: boot_ip,
        rsp: boot_sp,
        rbp: boot_sp,
        rsi: boot_si,
        ..Default::default()
    };

    vcpu.set_regs(&regs).map_err(Error::SettingRegistersIoctl)?;

    Ok(())
}

const X86_CR0_PE: u64 = 0x1;
const X86_CR0_PG: u64 = 0x80000000;
const X86_CR4_PAE: u64 = 0x20;

const EFER_LMA: u64 = 0x400;
const EFER_LME: u64 = 0x100;

const BOOT_GDT_OFFSET: usize = 0x500;
const BOOT_IDT_OFFSET: usize = 0x520;

const BOOT_GDT_MAX: usize = 4;

fn write_gdt_table(table: &[u64], guest_mem: &GuestMemory) -> Result<()> {
    let boot_gdt_addr = GuestAddress(BOOT_GDT_OFFSET);
    for (index, entry) in table.iter().enumerate() {
        let addr = guest_mem
            .checked_offset(boot_gdt_addr, index * mem::size_of::<u64>())
            .ok_or(Error::WriteGDTFailure)?;
        guest_mem
            .write_obj_at_addr(*entry, addr)
            .map_err(|_| Error::WriteGDTFailure)?;
    }
    Ok(())
}

fn write_idt_value(val: u64, guest_mem: &GuestMemory) -> Result<()> {
    let boot_idt_addr = GuestAddress(BOOT_IDT_OFFSET);
    guest_mem
        .write_obj_at_addr(val, boot_idt_addr)
        .map_err(|_| Error::WriteIDTFailure)
}

fn configure_segments_and_sregs(mem: &GuestMemory, sregs: &mut kvm_sregs) -> Result<()> {
    let gdt_table: [u64; BOOT_GDT_MAX as usize] = [
        gdt::gdt_entry(0, 0, 0),            // NULL
        gdt::gdt_entry(0xa09b, 0, 0xfffff), // CODE
        gdt::gdt_entry(0xc093, 0, 0xfffff), // DATA
        gdt::gdt_entry(0x808b, 0, 0xfffff), // TSS
    ];

    let code_seg = gdt::kvm_segment_from_gdt(gdt_table[1], 1);
    let data_seg = gdt::kvm_segment_from_gdt(gdt_table[2], 2);
    let tss_seg = gdt::kvm_segment_from_gdt(gdt_table[3], 3);

    // Write segments
    write_gdt_table(&gdt_table[..], mem)?;
    sregs.gdt.base = BOOT_GDT_OFFSET as u64;
    sregs.gdt.limit = mem::size_of_val(&gdt_table) as u16 - 1;

    write_idt_value(0, mem)?;
    sregs.idt.base = BOOT_IDT_OFFSET as u64;
    sregs.idt.limit = mem::size_of::<u64>() as u16 - 1;

    sregs.cs = code_seg;
    sregs.ds = data_seg;
    sregs.es = data_seg;
    sregs.fs = data_seg;
    sregs.gs = data_seg;
    sregs.ss = data_seg;
    sregs.tr = tss_seg;

    /* 64-bit protected mode */
    sregs.cr0 |= X86_CR0_PE;
    sregs.efer |= EFER_LME | EFER_LMA;

    Ok(())
}

fn setup_page_tables(mem: &GuestMemory, sregs: &mut kvm_sregs) -> Result<()> {
    // Puts PML4 right after zero page but aligned to 4k.
    let boot_pml4_addr = GuestAddress(layout::PML4_START);
    let boot_pdpte_addr = GuestAddress(layout::PDPTE_START);

    mem.write_obj_at_addr(boot_pdpte_addr.offset() as u64 | 0x03, boot_pml4_addr)
        .map_err(|_| Error::WritePML4Address)?;
    mem.write_obj_at_addr(0x83u64, boot_pdpte_addr)
        .map_err(|_| Error::WritePDPTEAddress)?;
    sregs.cr3 = boot_pml4_addr.offset() as u64;
    sregs.cr4 |= X86_CR4_PAE;
    sregs.cr0 |= X86_CR0_PG;
    Ok(())
}

/// Configures the segment registers and system page tables for a given CPU.
///
/// # Arguments
///
/// * `mem` - The memory that will be passed to the guest.
/// * `vcpu_fd` - The FD returned from the KVM_CREATE_VCPU ioctl.
pub fn setup_sregs(mem: &GuestMemory, vcpu: &kvm::VcpuFd) -> Result<()> {
    let mut sregs: kvm_sregs = vcpu.get_sregs().map_err(Error::SRegsIoctlFailed)?;

    configure_segments_and_sregs(mem, &mut sregs)?;
    setup_page_tables(mem, &mut sregs)?; // TODO(dgreid) - Can this be done once per system instead?

    vcpu.set_sregs(&sregs).map_err(Error::SRegsIoctlFailed)?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use memory_model::{GuestAddress, GuestMemory};

    fn create_guest_mem() -> GuestMemory {
        GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap()
    }

    fn read_u64(gm: &GuestMemory, offset: usize) -> u64 {
        let read_addr = GuestAddress(offset);
        gm.read_obj_from_addr(read_addr).unwrap()
    }

    #[test]
    fn segments_and_sregs() {
        let mut sregs: kvm_sregs = Default::default();
        let gm = create_guest_mem();
        configure_segments_and_sregs(&gm, &mut sregs).unwrap();

        assert_eq!(0x0, read_u64(&gm, BOOT_GDT_OFFSET));
        assert_eq!(0xaf9b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 8));
        assert_eq!(0xcf93000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 16));
        assert_eq!(0x8f8b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 24));
        assert_eq!(0x0, read_u64(&gm, BOOT_IDT_OFFSET));

        assert_eq!(0, sregs.cs.base);
        assert_eq!(0xfffff, sregs.ds.limit);
        assert_eq!(0x10, sregs.es.selector);
        assert_eq!(1, sregs.fs.present);
        assert_eq!(1, sregs.gs.g);
        assert_eq!(0, sregs.ss.avl);
        assert_eq!(0, sregs.tr.base);
        assert_eq!(0xfffff, sregs.tr.limit);
        assert_eq!(0, sregs.tr.avl);
        assert_eq!(X86_CR0_PE, sregs.cr0);
        assert_eq!(EFER_LME | EFER_LMA, sregs.efer);
    }

    #[test]
    fn page_tables() {
        let mut sregs: kvm_sregs = Default::default();
        let gm = create_guest_mem();
        setup_page_tables(&gm, &mut sregs).unwrap();

        assert_eq!(0xa003, read_u64(&gm, layout::PML4_START));
        assert_eq!(0x83, read_u64(&gm, layout::PDPTE_START));

        assert_eq!(layout::PML4_START as u64, sregs.cr3);
        assert_eq!(X86_CR4_PAE, sregs.cr4);
        assert_eq!(X86_CR0_PG, sregs.cr0);
    }
}
<commit_msg>x86_64: refactoring regs before...<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::{mem, result};

use gdt;
use kvm;
use kvm_sys::kvm_fpu;
use kvm_sys::kvm_msr_entry;
use kvm_sys::kvm_msrs;
use kvm_sys::kvm_regs;
use kvm_sys::kvm_sregs;
use layout;
use memory_model::{GuestAddress, GuestMemory};
use sys_util;

#[derive(Debug)]
pub enum Error {
    /// Failed to configure the FPU.
    ConfigureFPU(sys_util::Error),
    /// Failed to set base registers for this CPU.
    ConfigureBaseRegisters(sys_util::Error),
    /// Setting up MSRs failed.
    ConfigureMSRs(sys_util::Error),
    /// Failed to set SREGs for this CPU.
    ConfigureSREGs(sys_util::Error),
    /// Writing the GDT to RAM failed.
    WriteGDT,
    /// Writing the IDT to RAM failed.
    WriteIDT,
    /// Writing PDPTE to RAM failed.
    WritePDPTEAddress,
    /// Writing PML4 to RAM failed.
    WritePML4Address,
}

pub type Result<T> = result::Result<T, Error>;

/// Configure Floating-Point Unit (FPU) registers for a given CPU.
///
/// # Arguments
///
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
pub fn setup_fpu(vcpu: &kvm::VcpuFd) -> Result<()> {
    let fpu: kvm_fpu = kvm_fpu {
        fcw: 0x37f,
        mxcsr: 0x1f80,
        ..Default::default()
    };

    vcpu.set_fpu(&fpu).map_err(Error::ConfigureFPU)
}

/// Configure Model Specific Registers (MSRs) for a given CPU.
///
/// # Arguments
///
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
pub fn setup_msrs(vcpu: &kvm::VcpuFd) -> Result<()> {
    let entry_vec = create_msr_entries();
    let vec_size_bytes =
        mem::size_of::<kvm_msrs>() + (entry_vec.len() * mem::size_of::<kvm_msr_entry>());
    let vec: Vec<u8> = Vec::with_capacity(vec_size_bytes);
    let msrs: &mut kvm_msrs = unsafe {
        // Converting the vector's memory to a struct is unsafe.  Carefully using the read-only
        // vector to size and set the members ensures no out-of-bounds errors below.
        &mut *(vec.as_ptr() as *mut kvm_msrs)
    };

    unsafe {
        // Mapping the unsized array to a slice is unsafe becase the length isn't known.
        // Providing the length used to create the struct guarantees the entire slice is valid.
        let entries: &mut [kvm_msr_entry] = msrs.entries.as_mut_slice(entry_vec.len());
        entries.copy_from_slice(&entry_vec);
    }
    msrs.nmsrs = entry_vec.len() as u32;

    vcpu.set_msrs(msrs).map_err(Error::ConfigureMSRs)
}

/// Configure base registers for a given CPU.
///
/// # Arguments
///
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
/// * `boot_ip` - Starting instruction pointer.
/// * `boot_sp` - Starting stack pointer.
/// * `boot_si` - Must point to zero page address per Linux ABI.
pub fn setup_regs(vcpu: &kvm::VcpuFd, boot_ip: u64, boot_sp: u64, boot_si: u64) -> Result<()> {
    let regs: kvm_regs = kvm_regs {
        rflags: 0x0000000000000002u64,
        rip: boot_ip,
        rsp: boot_sp,
        rbp: boot_sp,
        rsi: boot_si,
        ..Default::default()
    };

    vcpu.set_regs(&regs).map_err(Error::ConfigureBaseRegisters)
}

/// Configures the segment registers and system page tables for a given CPU.
///
/// # Arguments
///
/// * `mem` - The memory that will be passed to the guest.
/// * `vcpu` - Structure for the VCPU that holds the VCPU's fd.
pub fn setup_sregs(mem: &GuestMemory, vcpu: &kvm::VcpuFd) -> Result<()> {
    let mut sregs: kvm_sregs = vcpu.get_sregs().map_err(Error::ConfigureSREGs)?;

    configure_segments_and_sregs(mem, &mut sregs)?;
    setup_page_tables(mem, &mut sregs)?; // TODO(dgreid) - Can this be done once per system instead?

    vcpu.set_sregs(&sregs).map_err(Error::ConfigureSREGs)
}

const BOOT_GDT_OFFSET: usize = 0x500;
const BOOT_IDT_OFFSET: usize = 0x520;

const BOOT_GDT_MAX: usize = 4;

const EFER_LMA: u64 = 0x400;
const EFER_LME: u64 = 0x100;

const X86_CR0_PE: u64 = 0x1;
const X86_CR0_PG: u64 = 0x80000000;
const X86_CR4_PAE: u64 = 0x20;

fn write_gdt_table(table: &[u64], guest_mem: &GuestMemory) -> Result<()> {
    let boot_gdt_addr = GuestAddress(BOOT_GDT_OFFSET);
    for (index, entry) in table.iter().enumerate() {
        let addr = guest_mem
            .checked_offset(boot_gdt_addr, index * mem::size_of::<u64>())
            .ok_or(Error::WriteGDT)?;
        guest_mem
            .write_obj_at_addr(*entry, addr)
            .map_err(|_| Error::WriteGDT)?;
    }
    Ok(())
}

fn write_idt_value(val: u64, guest_mem: &GuestMemory) -> Result<()> {
    let boot_idt_addr = GuestAddress(BOOT_IDT_OFFSET);
    guest_mem
        .write_obj_at_addr(val, boot_idt_addr)
        .map_err(|_| Error::WriteIDT)
}

fn configure_segments_and_sregs(mem: &GuestMemory, sregs: &mut kvm_sregs) -> Result<()> {
    let gdt_table: [u64; BOOT_GDT_MAX as usize] = [
        gdt::gdt_entry(0, 0, 0),            // NULL
        gdt::gdt_entry(0xa09b, 0, 0xfffff), // CODE
        gdt::gdt_entry(0xc093, 0, 0xfffff), // DATA
        gdt::gdt_entry(0x808b, 0, 0xfffff), // TSS
    ];

    let code_seg = gdt::kvm_segment_from_gdt(gdt_table[1], 1);
    let data_seg = gdt::kvm_segment_from_gdt(gdt_table[2], 2);
    let tss_seg = gdt::kvm_segment_from_gdt(gdt_table[3], 3);

    // Write segments
    write_gdt_table(&gdt_table[..], mem)?;
    sregs.gdt.base = BOOT_GDT_OFFSET as u64;
    sregs.gdt.limit = mem::size_of_val(&gdt_table) as u16 - 1;

    write_idt_value(0, mem)?;
    sregs.idt.base = BOOT_IDT_OFFSET as u64;
    sregs.idt.limit = mem::size_of::<u64>() as u16 - 1;

    sregs.cs = code_seg;
    sregs.ds = data_seg;
    sregs.es = data_seg;
    sregs.fs = data_seg;
    sregs.gs = data_seg;
    sregs.ss = data_seg;
    sregs.tr = tss_seg;

    /* 64-bit protected mode */
    sregs.cr0 |= X86_CR0_PE;
    sregs.efer |= EFER_LME | EFER_LMA;

    Ok(())
}

fn setup_page_tables(mem: &GuestMemory, sregs: &mut kvm_sregs) -> Result<()> {
    // Puts PML4 right after zero page but aligned to 4k.
    let boot_pml4_addr = GuestAddress(layout::PML4_START);
    let boot_pdpte_addr = GuestAddress(layout::PDPTE_START);

    mem.write_obj_at_addr(boot_pdpte_addr.offset() as u64 | 0x03, boot_pml4_addr)
        .map_err(|_| Error::WritePML4Address)?;
    mem.write_obj_at_addr(0x83u64, boot_pdpte_addr)
        .map_err(|_| Error::WritePDPTEAddress)?;
    sregs.cr3 = boot_pml4_addr.offset() as u64;
    sregs.cr4 |= X86_CR4_PAE;
    sregs.cr0 |= X86_CR0_PG;
    Ok(())
}

fn create_msr_entries() -> Vec<kvm_msr_entry> {
    let mut entries = Vec::<kvm_msr_entry>::new();

    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_IA32_SYSENTER_CS,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_IA32_SYSENTER_ESP,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_IA32_SYSENTER_EIP,
        data: 0x0,
        ..Default::default()
    });
    // x86_64 specific msrs, we only run on x86_64 not x86.
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_STAR,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_CSTAR,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_KERNEL_GS_BASE,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_SYSCALL_MASK,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_LSTAR,
        data: 0x0,
        ..Default::default()
    });
    // end of x86_64 specific code
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_IA32_TSC,
        data: 0x0,
        ..Default::default()
    });
    entries.push(kvm_msr_entry {
        index: ::msr_index::MSR_IA32_MISC_ENABLE,
        data: ::msr_index::MSR_IA32_MISC_ENABLE_FAST_STRING as u64,
        ..Default::default()
    });

    entries
}

#[cfg(test)]
mod tests {
    use super::*;
    use memory_model::{GuestAddress, GuestMemory};

    fn create_guest_mem() -> GuestMemory {
        GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap()
    }

    fn read_u64(gm: &GuestMemory, offset: usize) -> u64 {
        let read_addr = GuestAddress(offset);
        gm.read_obj_from_addr(read_addr).unwrap()
    }

    #[test]
    fn segments_and_sregs() {
        let mut sregs: kvm_sregs = Default::default();
        let gm = create_guest_mem();
        configure_segments_and_sregs(&gm, &mut sregs).unwrap();

        assert_eq!(0x0, read_u64(&gm, BOOT_GDT_OFFSET));
        assert_eq!(0xaf9b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 8));
        assert_eq!(0xcf93000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 16));
        assert_eq!(0x8f8b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 24));
        assert_eq!(0x0, read_u64(&gm, BOOT_IDT_OFFSET));

        assert_eq!(0, sregs.cs.base);
        assert_eq!(0xfffff, sregs.ds.limit);
        assert_eq!(0x10, sregs.es.selector);
        assert_eq!(1, sregs.fs.present);
        assert_eq!(1, sregs.gs.g);
        assert_eq!(0, sregs.ss.avl);
        assert_eq!(0, sregs.tr.base);
        assert_eq!(0xfffff, sregs.tr.limit);
        assert_eq!(0, sregs.tr.avl);
        assert_eq!(X86_CR0_PE, sregs.cr0);
        assert_eq!(EFER_LME | EFER_LMA, sregs.efer);
    }

    #[test]
    fn page_tables() {
        let mut sregs: kvm_sregs = Default::default();
        let gm = create_guest_mem();
        setup_page_tables(&gm, &mut sregs).unwrap();

        assert_eq!(0xa003, read_u64(&gm, layout::PML4_START));
        assert_eq!(0x83, read_u64(&gm, layout::PDPTE_START));

        assert_eq!(layout::PML4_START as u64, sregs.cr3);
        assert_eq!(X86_CR4_PAE, sregs.cr4);
        assert_eq!(X86_CR0_PG, sregs.cr0);
    }
}
<|endoftext|>


<commit_before>extern crate nannou;

use nannou::prelude::*;

fn main() {
    nannou::view(view);
}

fn view(app: &App, frame: Frame) -> Frame {
    // Prepare to draw.
    let draw = app.draw();

    draw.background().color(LIGHT_PURPLE);

    if app.mouse.x < 0.0 {
        draw.ellipse().color(DARK_BLUE);
    } else {
        draw.ellipse().color(DARK_GREEN);
    }

    // Write to the window frame.
    draw.to_frame(app, &frame).unwrap();

    // Return the drawn frame.
    frame
}
<commit_msg>Added in a match statement to the 4_conditionals example<commit_after>extern crate nannou;

use nannou::prelude::*;

fn main() {
    nannou::view(view);
}

fn view(app: &App, frame: Frame) -> Frame {
    // Prepare to draw.
    let draw = app.draw();

    let win = app.window_rect();

    let color_select = map_range(app.mouse.y, win.top(), win.bottom(), 0.0, 5.0) as i32;

    let bg_color = match color_select {
        0 => RED,
        1 => ORANGE,
        2 => YELLOW,
        3 => GREEN,
        4 => BLUE,
        _ => BLACK,
    };

    draw.background().color(bg_color);

    if app.mouse.x < 0.0 {
        draw.ellipse().color(DARK_BLUE);
    } else {
        draw.ellipse().color(DARK_GREEN);
    }

    // Write to the window frame.
    draw.to_frame(app, &frame).unwrap();

    // Return the drawn frame.
    frame
}
<|endoftext|>


<commit_before>use super::*;
use crate::prelude::*;

use crate::guid::GUID;
use syn::{LitStr, Path};

#[derive(Debug, Clone)]
pub enum LibraryItemType
{
    Module(Path),
    Class(Path),
    Interface(Path),
}

impl syn::parse::Parse for LibraryItemType
{
    fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self>
    {
        let ident: syn::Ident = input.parse()?;
        match ident.to_string().as_str() {
            "module" => Ok(LibraryItemType::Module(input.parse()?)),
            "class" => Ok(LibraryItemType::Class(input.parse()?)),
            "interface" => Ok(LibraryItemType::Interface(input.parse()?)),
            _ => Err(input.error(&format!(
                    "Expected 'class', 'interface' or 'module', found {}", ident
            ))),
        }
    }
}

intercom_attribute!(
    ComLibraryAttr< ComLibraryAttrParam, LibraryItemType > {
        libid : LitStr,
    }
);

const EMPTY: [Path; 0] = [];

/// COM library details derived from the `com_library` attribute.
#[derive(Debug, PartialEq)]
pub struct ComLibrary
{
    pub name: String,
    pub libid: GUID,
    pub coclasses: Vec<Path>,
    pub interfaces: Vec<Path>,
    pub sub_modules: Vec<Path>,
}

impl ComLibrary
{
    /// Parses a [com_library] attribute.
    pub fn parse(crate_name: &str, attr_params: TokenStream) -> ParseResult<ComLibrary>
    {
        let attr: ComLibraryAttr = ::syn::parse2(attr_params)
            .map_err(|_| ParseError::ComLibrary("Attribute syntax error".into()))?;

        // The first parameter is the LIBID of the library.
        let libid = match attr.libid().map_err(ParseError::ComLibrary)? {
            Some(libid) => GUID::parse(&libid.value()).map_err(ParseError::ComLibrary)?,
            None => crate::utils::generate_libid(crate_name),
        };

        let mut coclasses = vec![];
        let mut interfaces = vec![];
        let mut sub_modules = vec![];
        for arg in attr.args().into_iter().cloned() {
            match arg {
                LibraryItemType::Class(cls) => coclasses.push(cls),
                LibraryItemType::Interface(cls) => interfaces.push(cls),
                LibraryItemType::Module(cls) => sub_modules.push(cls),
            }
        }

        Ok(ComLibrary {
            name: crate_name.to_owned(),
            coclasses,
            interfaces,
            sub_modules,
            libid,
        })
    }

    /// CoClasses exposed by the library.
    pub fn interfaces(&self) -> &[Path]
    {
        &EMPTY
    }

    /// Adds a coclass.
    pub fn add_coclass(&mut self, clsid: Path)
    {
        self.coclasses.push(clsid)
    }
}

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

    #[test]
    fn parse_com_library()
    {
        let lib = ComLibrary::parse(
            "library_name".into(),
            quote!(libid = "12345678-1234-1234-1234-567890ABCDEF", Foo, Bar),
        )
        .expect("com_library attribute parsing failed");

        assert_eq!(lib.name, "library_name");
        assert_eq!(
            lib.libid,
            GUID {
                data1: 0x12345678,
                data2: 0x1234,
                data3: 0x1234,
                data4: [0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF]
            }
        );
        assert_eq!(lib.coclasses.len(), 2);
        assert_eq!(lib.coclasses[0], parse_quote!(Foo));
        assert_eq!(lib.coclasses[1], parse_quote!(Bar));
    }

    #[test]
    fn parse_com_library_with_auto_guid()
    {
        // This test derives the GUID from the library name.
        //
        // What the final GUID is isn't important, what _is_ important however
        // is that the final GUID will not change ever as long as the library
        // name stays the same.
        let lib = ComLibrary::parse("another_library".into(), quote!(One, Two))
            .expect("com_library attribute parsing failed");

        assert_eq!(lib.name, "another_library");
        assert_eq!(
            lib.libid,
            GUID::parse("696B2FAE-AC56-3E08-7C2C-ABAA8DB8F6E3").unwrap()
        );
        assert_eq!(lib.coclasses.len(), 2);
        assert_eq!(lib.coclasses[0], parse_quote!(One));
        assert_eq!(lib.coclasses[1], parse_quote!(Two));
    }

    #[test]
    fn parse_com_library_with_empty_parameters()
    {
        let lib = ComLibrary::parse("lib".into(), quote!()).unwrap();
        assert_eq!(lib.coclasses.len(), 0);
        assert_eq!(
            lib.libid,
            GUID::parse("22EC0095-CD17-3AFD-6C4F-531464178911").unwrap()
        );
    }
}
<commit_msg>Rename sub_modules -> submodules<commit_after>use super::*;
use crate::prelude::*;

use crate::guid::GUID;
use syn::{LitStr, Path};

#[derive(Debug, Clone)]
pub enum LibraryItemType
{
    Module(Path),
    Class(Path),
    Interface(Path),
}

impl syn::parse::Parse for LibraryItemType
{
    fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self>
    {
        let ident: syn::Ident = input.parse()?;
        match ident.to_string().as_str() {
            "module" => Ok(LibraryItemType::Module(input.parse()?)),
            "class" => Ok(LibraryItemType::Class(input.parse()?)),
            "interface" => Ok(LibraryItemType::Interface(input.parse()?)),
            _ => Err(input.error(&format!(
                    "Expected 'class', 'interface' or 'module', found {}", ident
            ))),
        }
    }
}

intercom_attribute!(
    ComLibraryAttr< ComLibraryAttrParam, LibraryItemType > {
        libid : LitStr,
    }
);

const EMPTY: [Path; 0] = [];

/// COM library details derived from the `com_library` attribute.
#[derive(Debug, PartialEq)]
pub struct ComLibrary
{
    pub name: String,
    pub libid: GUID,
    pub coclasses: Vec<Path>,
    pub interfaces: Vec<Path>,
    pub submodules: Vec<Path>,
}

impl ComLibrary
{
    /// Parses a [com_library] attribute.
    pub fn parse(crate_name: &str, attr_params: TokenStream) -> ParseResult<ComLibrary>
    {
        let attr: ComLibraryAttr = ::syn::parse2(attr_params)
            .map_err(|_| ParseError::ComLibrary("Attribute syntax error".into()))?;

        // The first parameter is the LIBID of the library.
        let libid = match attr.libid().map_err(ParseError::ComLibrary)? {
            Some(libid) => GUID::parse(&libid.value()).map_err(ParseError::ComLibrary)?,
            None => crate::utils::generate_libid(crate_name),
        };

        let mut coclasses = vec![];
        let mut interfaces = vec![];
        let mut submodules = vec![];
        for arg in attr.args().into_iter().cloned() {
            match arg {
                LibraryItemType::Class(cls) => coclasses.push(cls),
                LibraryItemType::Interface(cls) => interfaces.push(cls),
                LibraryItemType::Module(cls) => submodules.push(cls),
            }
        }

        Ok(ComLibrary {
            name: crate_name.to_owned(),
            coclasses,
            interfaces,
            submodules,
            libid,
        })
    }

    /// CoClasses exposed by the library.
    pub fn interfaces(&self) -> &[Path]
    {
        &EMPTY
    }

    /// Adds a coclass.
    pub fn add_coclass(&mut self, clsid: Path)
    {
        self.coclasses.push(clsid)
    }
}

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

    #[test]
    fn parse_com_library()
    {
        let lib = ComLibrary::parse(
            "library_name".into(),
            quote!(libid = "12345678-1234-1234-1234-567890ABCDEF", Foo, Bar),
        )
        .expect("com_library attribute parsing failed");

        assert_eq!(lib.name, "library_name");
        assert_eq!(
            lib.libid,
            GUID {
                data1: 0x12345678,
                data2: 0x1234,
                data3: 0x1234,
                data4: [0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF]
            }
        );
        assert_eq!(lib.coclasses.len(), 2);
        assert_eq!(lib.coclasses[0], parse_quote!(Foo));
        assert_eq!(lib.coclasses[1], parse_quote!(Bar));
    }

    #[test]
    fn parse_com_library_with_auto_guid()
    {
        // This test derives the GUID from the library name.
        //
        // What the final GUID is isn't important, what _is_ important however
        // is that the final GUID will not change ever as long as the library
        // name stays the same.
        let lib = ComLibrary::parse("another_library".into(), quote!(One, Two))
            .expect("com_library attribute parsing failed");

        assert_eq!(lib.name, "another_library");
        assert_eq!(
            lib.libid,
            GUID::parse("696B2FAE-AC56-3E08-7C2C-ABAA8DB8F6E3").unwrap()
        );
        assert_eq!(lib.coclasses.len(), 2);
        assert_eq!(lib.coclasses[0], parse_quote!(One));
        assert_eq!(lib.coclasses[1], parse_quote!(Two));
    }

    #[test]
    fn parse_com_library_with_empty_parameters()
    {
        let lib = ComLibrary::parse("lib".into(), quote!()).unwrap();
        assert_eq!(lib.coclasses.len(), 0);
        assert_eq!(
            lib.libid,
            GUID::parse("22EC0095-CD17-3AFD-6C4F-531464178911").unwrap()
        );
    }
}
<|endoftext|>


<commit_before>use crate::util;
use core::cell::Cell;
use libtock_core::{callback, syscalls};

const DRIVER_NUMBER: usize = 0x30003;

mod command_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
    pub const EMULATE: usize = 3;
    pub const CONFIGURE: usize = 4;
}

mod subscribe_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
    pub const SELECT: usize = 3;
}

mod allow_nr {
    pub const TRANSMIT: usize = 1;
    pub const RECEIVE: usize = 2;
}

pub fn enable_emulation() {
    emulate(true);
}

pub fn disable_emulation() {
    emulate(false);
}

pub fn emulate(enabled: bool) -> bool {
    let result_code = syscalls::command(DRIVER_NUMBER, command_nr::EMULATE, enabled as usize, 0);
    if result_code.is_err() {
        return false;
    }

    true
}

pub fn selected() -> bool {
    let is_selected = Cell::new(false);
    let mut is_selected_alarm = || is_selected.set(true);
    let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
        DRIVER_NUMBER,
        subscribe_nr::SELECT,
        &mut is_selected_alarm,
    );
    if subscription.is_err() {
        return false;
    }

    util::yieldk_for(|| is_selected.get());
    true
}

pub fn configure(tag_type: u8) -> bool {
    let result_code = syscalls::command(DRIVER_NUMBER, command_nr::CONFIGURE, tag_type as usize, 0);
    if result_code.is_err() {
        return false;
    }

    true
}

pub fn receive(buf: &mut [u8]) -> bool {
    let result = syscalls::allow(DRIVER_NUMBER, allow_nr::RECEIVE, buf);
    if result.is_err() {
        return false;
    }

    let done = Cell::new(false);
    let mut alarm = || done.set(true);
    let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
        DRIVER_NUMBER,
        subscribe_nr::RECEIVE,
        &mut alarm,
    );
    if subscription.is_err() {
        return false;
    }

    let result_code = syscalls::command(DRIVER_NUMBER, command_nr::RECEIVE, 0, 0);
    if result_code.is_err() {
        return false;
    }

    util::yieldk_for(|| done.get());
    true
}

pub fn transmit(buf: &mut [u8]) -> bool {
    let result = syscalls::allow(DRIVER_NUMBER, allow_nr::TRANSMIT, buf);
    if result.is_err() {
        return false;
    }

    let done = Cell::new(false);
    let mut alarm = || done.set(true);
    let subscription = syscalls::subscribe::<callback::Identity0Consumer, _>(
        DRIVER_NUMBER,
        subscribe_nr::TRANSMIT,
        &mut alarm,
    );
    if subscription.is_err() {
        return false;
    }

    let result_code = syscalls::command(DRIVER_NUMBER, command_nr::TRANSMIT, 0, 0);
    if result_code.is_err() {
        return false;
    }

    util::yieldk_for(|| done.get());
    true
}
<commit_msg>Delete nfc.rs<commit_after><|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! An actor-based remote devtools server implementation. Only tested with
//! nightly Firefox versions at time of writing. Largely based on
//! reverse-engineering of Firefox chrome devtool logs and reading of
//! [code](http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/).

#![crate_name = "devtools"]
#![crate_type = "rlib"]

#![feature(box_syntax, core, rustc_private)]
#![feature(collections, std_misc)]
#![feature(io)]
#![feature(net)]
#![feature(old_io)]

#![allow(non_snake_case)]

#[macro_use]
extern crate log;

extern crate collections;
extern crate core;
extern crate devtools_traits;
extern crate "rustc-serialize" as rustc_serialize;
extern crate msg;
extern crate time;
extern crate util;

use actor::{Actor, ActorRegistry};
use actors::console::ConsoleActor;
use actors::worker::WorkerActor;
use actors::inspector::InspectorActor;
use actors::root::RootActor;
use actors::tab::TabActor;
use actors::timeline::TimelineActor;
use protocol::JsonPacketStream;

use devtools_traits::{ConsoleMessage, DevtoolsControlMsg};
use devtools_traits::{DevtoolsPageInfo, DevtoolScriptControlMsg};
use msg::constellation_msg::{PipelineId, WorkerId};
use util::task::spawn_named;

use std::borrow::ToOwned;
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::mpsc::{channel, Receiver, Sender, RecvError};
use std::net::{TcpListener, TcpStream, Shutdown};
use std::sync::{Arc, Mutex};
use time::precise_time_ns;

mod actor;
/// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/
mod actors {
    pub mod console;
    pub mod framerate;
    pub mod memory;
    pub mod inspector;
    pub mod root;
    pub mod tab;
    pub mod timeline;
    pub mod worker;
}
mod protocol;

#[derive(RustcEncodable)]
struct ConsoleAPICall {
    from: String,
    __type__: String,
    message: ConsoleMsg,
}

#[derive(RustcEncodable)]
struct ConsoleMsg {
    level: String,
    timeStamp: u64,
    arguments: Vec<String>,
    filename: String,
    lineNumber: u32,
    columnNumber: u32,
}

/// Spin up a devtools server that listens for connections on the specified port.
pub fn start_server(port: u16) -> Sender<DevtoolsControlMsg> {
    let (sender, receiver) = channel();
    {
        let sender = sender.clone();
        spawn_named("Devtools".to_owned(), move || {
            run_server(sender, receiver, port)
        });
    }
    sender
}

fn run_server(sender: Sender<DevtoolsControlMsg>,
              receiver: Receiver<DevtoolsControlMsg>,
              port: u16) {
    let listener = TcpListener::bind(&("127.0.0.1", port)).unwrap();

    let mut registry = ActorRegistry::new();

    let root = box RootActor {
        tabs: vec!(),
    };

    registry.register(root);
    registry.find::<RootActor>("root");

    let actors = registry.create_shareable();

    let mut accepted_connections: Vec<TcpStream> = Vec::new();

    let mut actor_pipelines: HashMap<PipelineId, String> = HashMap::new();

    /// Process the input from a single devtools client until EOF.
    fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream) {
        println!("connection established to {}", stream.peer_addr().unwrap());
        {
            let actors = actors.lock().unwrap();
            let msg = actors.find::<RootActor>("root").encodable();
            stream.write_json_packet(&msg);
        }

        'outer: loop {
            match stream.read_json_packet() {
                Ok(json_packet) => {
                    match actors.lock().unwrap().handle_message(json_packet.as_object().unwrap(),
                                                                &mut stream) {
                        Ok(()) => {},
                        Err(()) => {
                            println!("error: devtools actor stopped responding");
                            let _ = stream.shutdown(Shutdown::Both);
                            break 'outer
                        }
                    }
                }
                Err(e) => {
                    println!("error: {}", e.description());
                    break 'outer
                }
            }
        }
    }

    // We need separate actor representations for each script global that exists;
    // clients can theoretically connect to multiple globals simultaneously.
    // TODO: move this into the root or tab modules?
    fn handle_new_global(actors: Arc<Mutex<ActorRegistry>>,
                         ids: (PipelineId, Option<WorkerId>),
                         scriptSender: Sender<DevtoolScriptControlMsg>,
                         actor_pipelines: &mut HashMap<PipelineId, String>,
                         page_info: DevtoolsPageInfo) {
        let mut actors = actors.lock().unwrap();

        let (pipeline, worker_id) = ids;

        let mut actor_workers: HashMap<(PipelineId, WorkerId), String> = HashMap::new();

        //TODO: move all this actor creation into a constructor method on TabActor
        let (tab, console, inspector, timeline) = {
            let console = ConsoleActor {
                name: actors.new_name("console"),
                script_chan: scriptSender.clone(),
                pipeline: pipeline,
                streams: RefCell::new(Vec::new()),
            };
            let inspector = InspectorActor {
                name: actors.new_name("inspector"),
                walker: RefCell::new(None),
                pageStyle: RefCell::new(None),
                highlighter: RefCell::new(None),
                script_chan: scriptSender.clone(),
                pipeline: pipeline,
            };

            let timeline = TimelineActor::new(actors.new_name("timeline"),
                                              pipeline,
                                              scriptSender);

            let DevtoolsPageInfo { title, url } = page_info;
            let tab = TabActor {
                name: actors.new_name("tab"),
                title: title,
                url: url.serialize(),
                console: console.name(),
                inspector: inspector.name(),
                timeline: timeline.name(),
            };

            let root = actors.find_mut::<RootActor>("root");
            root.tabs.push(tab.name.clone());
            (tab, console, inspector, timeline)
        };

        if let Some(id) = worker_id {
            let worker = WorkerActor {
                name: actors.new_name("worker"),
                id: id,
            };
            actor_workers.insert((pipeline, id), worker.name.clone());
            actors.register(box worker);
        }

        actor_pipelines.insert(pipeline, tab.name.clone());
        actors.register(box tab);
        actors.register(box console);
        actors.register(box inspector);
        actors.register(box timeline);
    }

    fn handle_console_message(actors: Arc<Mutex<ActorRegistry>>,
                              id: PipelineId,
                              console_message: ConsoleMessage,
                              actor_pipelines: &HashMap<PipelineId, String>) {
        let console_actor_name = find_console_actor(actors.clone(), id, actor_pipelines);
        let actors = actors.lock().unwrap();
        let console_actor = actors.find::<ConsoleActor>(&console_actor_name);
        match console_message {
            ConsoleMessage::LogMessage(message, filename, lineNumber, columnNumber) => {
                let msg = ConsoleAPICall {
                    from: console_actor.name.clone(),
                    __type__: "consoleAPICall".to_string(),
                    message: ConsoleMsg {
                        level: "log".to_string(),
                        timeStamp: precise_time_ns(),
                        arguments: vec!(message),
                        filename: filename,
                        lineNumber: lineNumber,
                        columnNumber: columnNumber,
                    },
                };
                for stream in console_actor.streams.borrow_mut().iter_mut() {
                    stream.write_json_packet(&msg);
                }
            }
        }
    }

    fn find_console_actor(actors: Arc<Mutex<ActorRegistry>>,
                          id: PipelineId,
                          actor_pipelines: &HashMap<PipelineId, String>) -> String {
        let actors = actors.lock().unwrap();
        let ref tab_actor_name = (*actor_pipelines)[id];
        let tab_actor = actors.find::<TabActor>(tab_actor_name);
        let console_actor_name = tab_actor.console.clone();
        return console_actor_name;
    }

    spawn_named("DevtoolsClientAcceptor".to_owned(), move || {
        // accept connections and process them, spawning a new task for each one
        for stream in listener.incoming() {
            // connection succeeded
            sender.send(DevtoolsControlMsg::AddClient(stream.unwrap())).unwrap();
        }
    });

    loop {
        match receiver.recv() {
            Ok(DevtoolsControlMsg::AddClient(stream)) => {
                let actors = actors.clone();
                accepted_connections.push(stream.try_clone().unwrap());
                spawn_named("DevtoolsClientHandler".to_owned(), move || {
                    handle_client(actors, stream.try_clone().unwrap())
                })
            }
            Ok(DevtoolsControlMsg::ServerExitMsg) | Err(RecvError) => break,
            Ok(DevtoolsControlMsg::NewGlobal(ids, scriptSender, pageinfo)) =>
                handle_new_global(actors.clone(), ids, scriptSender, &mut actor_pipelines,
                                  pageinfo),
            Ok(DevtoolsControlMsg::SendConsoleMessage(id, console_message)) =>
                handle_console_message(actors.clone(), id, console_message,
                                       &actor_pipelines),
        }
    }

    for connection in accepted_connections.iter_mut() {
        let _ = connection.shutdown(Shutdown::Both);
    }
}
<commit_msg>Auto merge of #5758 - dhananjay92:Issue#5735, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! An actor-based remote devtools server implementation. Only tested with
//! nightly Firefox versions at time of writing. Largely based on
//! reverse-engineering of Firefox chrome devtool logs and reading of
//! [code](http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/).

#![crate_name = "devtools"]
#![crate_type = "rlib"]

#![feature(box_syntax, core, rustc_private)]
#![feature(collections, std_misc)]
#![feature(io)]
#![feature(net)]
#![feature(old_io)]

#![allow(non_snake_case)]

#[macro_use]
extern crate log;

extern crate collections;
extern crate core;
extern crate devtools_traits;
extern crate "rustc-serialize" as rustc_serialize;
extern crate msg;
extern crate time;
extern crate util;

use actor::{Actor, ActorRegistry};
use actors::console::ConsoleActor;
use actors::worker::WorkerActor;
use actors::inspector::InspectorActor;
use actors::root::RootActor;
use actors::tab::TabActor;
use actors::timeline::TimelineActor;
use protocol::JsonPacketStream;

use devtools_traits::{ConsoleMessage, DevtoolsControlMsg};
use devtools_traits::{DevtoolsPageInfo, DevtoolScriptControlMsg};
use msg::constellation_msg::{PipelineId, WorkerId};
use util::task::spawn_named;

use std::borrow::ToOwned;
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::mpsc::{channel, Receiver, Sender, RecvError};
use std::net::{TcpListener, TcpStream, Shutdown};
use std::sync::{Arc, Mutex};
use time::precise_time_ns;

mod actor;
/// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/
mod actors {
    pub mod console;
    pub mod framerate;
    pub mod memory;
    pub mod inspector;
    pub mod root;
    pub mod tab;
    pub mod timeline;
    pub mod worker;
}
mod protocol;

#[derive(RustcEncodable)]
struct ConsoleAPICall {
    from: String,
    __type__: String,
    message: ConsoleMsg,
}

#[derive(RustcEncodable)]
struct ConsoleMsg {
    level: String,
    timeStamp: u64,
    arguments: Vec<String>,
    filename: String,
    lineNumber: u32,
    columnNumber: u32,
}

/// Spin up a devtools server that listens for connections on the specified port.
pub fn start_server(port: u16) -> Sender<DevtoolsControlMsg> {
    let (sender, receiver) = channel();
    {
        let sender = sender.clone();
        spawn_named("Devtools".to_owned(), move || {
            run_server(sender, receiver, port)
        });
    }
    sender
}

fn run_server(sender: Sender<DevtoolsControlMsg>,
              receiver: Receiver<DevtoolsControlMsg>,
              port: u16) {
    let listener = TcpListener::bind(&("127.0.0.1", port)).unwrap();

    let mut registry = ActorRegistry::new();

    let root = box RootActor {
        tabs: vec!(),
    };

    registry.register(root);
    registry.find::<RootActor>("root");

    let actors = registry.create_shareable();

    let mut accepted_connections: Vec<TcpStream> = Vec::new();

    let mut actor_pipelines: HashMap<PipelineId, String> = HashMap::new();

    let mut actor_workers: HashMap<(PipelineId, WorkerId), String> = HashMap::new();

    /// Process the input from a single devtools client until EOF.
    fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream) {
        println!("connection established to {}", stream.peer_addr().unwrap());
        {
            let actors = actors.lock().unwrap();
            let msg = actors.find::<RootActor>("root").encodable();
            stream.write_json_packet(&msg);
        }

        'outer: loop {
            match stream.read_json_packet() {
                Ok(json_packet) => {
                    match actors.lock().unwrap().handle_message(json_packet.as_object().unwrap(),
                                                                &mut stream) {
                        Ok(()) => {},
                        Err(()) => {
                            println!("error: devtools actor stopped responding");
                            let _ = stream.shutdown(Shutdown::Both);
                            break 'outer
                        }
                    }
                }
                Err(e) => {
                    println!("error: {}", e.description());
                    break 'outer
                }
            }
        }
    }

    // We need separate actor representations for each script global that exists;
    // clients can theoretically connect to multiple globals simultaneously.
    // TODO: move this into the root or tab modules?
    fn handle_new_global(actors: Arc<Mutex<ActorRegistry>>,
                         ids: (PipelineId, Option<WorkerId>),
                         scriptSender: Sender<DevtoolScriptControlMsg>,
                         actor_pipelines: &mut HashMap<PipelineId, String>,
                         actor_workers: &mut HashMap<(PipelineId, WorkerId), String>,
                         page_info: DevtoolsPageInfo) {
        let mut actors = actors.lock().unwrap();

        let (pipeline, worker_id) = ids;

        //TODO: move all this actor creation into a constructor method on TabActor
        let (tab, console, inspector, timeline) = {
            let console = ConsoleActor {
                name: actors.new_name("console"),
                script_chan: scriptSender.clone(),
                pipeline: pipeline,
                streams: RefCell::new(Vec::new()),
            };
            let inspector = InspectorActor {
                name: actors.new_name("inspector"),
                walker: RefCell::new(None),
                pageStyle: RefCell::new(None),
                highlighter: RefCell::new(None),
                script_chan: scriptSender.clone(),
                pipeline: pipeline,
            };

            let timeline = TimelineActor::new(actors.new_name("timeline"),
                                              pipeline,
                                              scriptSender);

            let DevtoolsPageInfo { title, url } = page_info;
            let tab = TabActor {
                name: actors.new_name("tab"),
                title: title,
                url: url.serialize(),
                console: console.name(),
                inspector: inspector.name(),
                timeline: timeline.name(),
            };

            let root = actors.find_mut::<RootActor>("root");
            root.tabs.push(tab.name.clone());
            (tab, console, inspector, timeline)
        };

        if let Some(id) = worker_id {
            let worker = WorkerActor {
                name: actors.new_name("worker"),
                id: id,
            };
            actor_workers.insert((pipeline, id), worker.name.clone());
            actors.register(box worker);
        }

        actor_pipelines.insert(pipeline, tab.name.clone());
        actors.register(box tab);
        actors.register(box console);
        actors.register(box inspector);
        actors.register(box timeline);
    }

    fn handle_console_message(actors: Arc<Mutex<ActorRegistry>>,
                              id: PipelineId,
                              console_message: ConsoleMessage,
                              actor_pipelines: &HashMap<PipelineId, String>) {
        let console_actor_name = find_console_actor(actors.clone(), id, actor_pipelines);
        let actors = actors.lock().unwrap();
        let console_actor = actors.find::<ConsoleActor>(&console_actor_name);
        match console_message {
            ConsoleMessage::LogMessage(message, filename, lineNumber, columnNumber) => {
                let msg = ConsoleAPICall {
                    from: console_actor.name.clone(),
                    __type__: "consoleAPICall".to_string(),
                    message: ConsoleMsg {
                        level: "log".to_string(),
                        timeStamp: precise_time_ns(),
                        arguments: vec!(message),
                        filename: filename,
                        lineNumber: lineNumber,
                        columnNumber: columnNumber,
                    },
                };
                for stream in console_actor.streams.borrow_mut().iter_mut() {
                    stream.write_json_packet(&msg);
                }
            }
        }
    }

    fn find_console_actor(actors: Arc<Mutex<ActorRegistry>>,
                          id: PipelineId,
                          actor_pipelines: &HashMap<PipelineId, String>) -> String {
        let actors = actors.lock().unwrap();
        let ref tab_actor_name = (*actor_pipelines)[id];
        let tab_actor = actors.find::<TabActor>(tab_actor_name);
        let console_actor_name = tab_actor.console.clone();
        return console_actor_name;
    }

    spawn_named("DevtoolsClientAcceptor".to_owned(), move || {
        // accept connections and process them, spawning a new task for each one
        for stream in listener.incoming() {
            // connection succeeded
            sender.send(DevtoolsControlMsg::AddClient(stream.unwrap())).unwrap();
        }
    });

    loop {
        match receiver.recv() {
            Ok(DevtoolsControlMsg::AddClient(stream)) => {
                let actors = actors.clone();
                accepted_connections.push(stream.try_clone().unwrap());
                spawn_named("DevtoolsClientHandler".to_owned(), move || {
                    handle_client(actors, stream.try_clone().unwrap())
                })
            }
            Ok(DevtoolsControlMsg::ServerExitMsg) | Err(RecvError) => break,
            Ok(DevtoolsControlMsg::NewGlobal(ids, scriptSender, pageinfo)) =>
                handle_new_global(actors.clone(), ids, scriptSender, &mut actor_pipelines,
                                  &mut actor_workers, pageinfo),
            Ok(DevtoolsControlMsg::SendConsoleMessage(id, console_message)) =>
                handle_console_message(actors.clone(), id, console_message,
                                       &actor_pipelines),
        }
    }

    for connection in accepted_connections.iter_mut() {
        let _ = connection.shutdown(Shutdown::Both);
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Result, copy, stdout};
use std::env::args_os;
use std::process::exit;
use std::ffi::OsString;
use std::fs::File;
use std::path::Path;

extern crate concat;
use concat::concat;

fn main() {
    let mut args = args_os();
    let progname = args.next().unwrap_or_else(|| OsString::from("cat"));

    let mut c = concat(args.map(InputSource::from));
    let res = copy(&mut c, &mut stdout());

    if let Err(e) = res {
        match c.current() {
            None => {
                println!("{}: {}\n",
                         AsRef::<Path>::as_ref(&progname).display(),
                         e);
            },

            Some(ref f) => {
                println!("{}: {}: {}\n",
                         AsRef::<Path>::as_ref(&progname).display(),
                         f.path().display(),
                         e);
            },
        };

        exit(1);
    }
}

struct InputSource {
    path: OsString,
    file: Option<File>,
}

impl InputSource {
    pub fn path(&self) -> &Path {
        self.path.as_ref()
    }
}

impl From<OsString> for InputSource {
    fn from(path: OsString) -> InputSource {
        InputSource {
            path: path,
            file: None,
        }
    }
}

impl Read for InputSource {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        if self.file.is_none() {
            self.file = Some(try!(File::open(&self.path)));
        }

        self.file.as_mut().unwrap().read(buf)
    }
}
<commit_msg>make cat print error messages to stderr<commit_after>use std::io::{Result, Read, Write, copy, stdout, stderr};
use std::env::args_os;
use std::process::exit;
use std::ffi::OsString;
use std::fs::File;
use std::path::Path;

extern crate concat;
use concat::concat;

fn main() {
    let mut args = args_os();
    let progname = args.next().unwrap_or_else(|| OsString::from("cat"));

    let mut c = concat(args.map(InputSource::from));
    let res = copy(&mut c, &mut stdout());

    if let Err(e) = res {
        match c.current() {
            None => {
                writeln!(&mut stderr(),
                         "{}: {}\n",
                         AsRef::<Path>::as_ref(&progname).display(),
                         e).unwrap();
            },

            Some(ref f) => {
                writeln!(&mut stderr(),
                         "{}: {}: {}\n",
                         AsRef::<Path>::as_ref(&progname).display(),
                         f.path().display(),
                         e).unwrap();
            },
        };

        exit(1);
    }
}

struct InputSource {
    path: OsString,
    file: Option<File>,
}

impl InputSource {
    pub fn path(&self) -> &Path {
        self.path.as_ref()
    }
}

impl From<OsString> for InputSource {
    fn from(path: OsString) -> InputSource {
        InputSource {
            path: path,
            file: None,
        }
    }
}

impl Read for InputSource {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        if self.file.is_none() {
            self.file = Some(try!(File::open(&self.path)));
        }

        self.file.as_mut().unwrap().read(buf)
    }
}
<|endoftext|>


<commit_before>extern crate three;
extern crate mint;
extern crate froggy;

use std::env;
use three::Geometry;
use mint::Point3;
use froggy::WeakPointer;

fn main() {
    let mut args = env::args();
    let obj_path = concat!(env!("CARGO_MANIFEST_DIR"), "/test_data/sample.stl");
    let path = args.nth(1).unwrap_or(obj_path.into());
    let mut vertices = vec!();

    match stlv::parser::load_file(path.as_str()) {
        Ok(model) => {
            for triangle in (*model).iter() {
                let stl_vertices = triangle.vertices();
                vertices.push(Point3{x: stl_vertices[0].get_x(), y: stl_vertices[0].get_y(),
                    z: stl_vertices[0].get_z()});
                vertices.push(Point3{x: stl_vertices[1].get_x(), y: stl_vertices[1].get_y(),
                    z: stl_vertices[1].get_z()});
                vertices.push(Point3{x: stl_vertices[2].get_x(), y: stl_vertices[2].get_y(),
                    z: stl_vertices[2].get_z()});
            }
        }
        _ => panic!("Failed to parse the STL file {}", path),
    }

    let geometry = Geometry::with_vertices(vertices);

     // Upload the triangle data to the GPU.
    let mut window = three::Window::new("Three-rs obj loading example");
    let upload_geometry = window.factory.upload_geometry(geometry);

     // Create multiple meshes with the same GPU data and material.
     let material = three::material::Basic {
         color: 0xFFFF00,
         map: None,
     };

    window.factory.create_instanced_mesh(&upload_geometry, material.clone());

    let cam = window.factory.perspective_camera(60.0, 1.0 .. 1000.0);
    let mut controls = three::controls::Orbit::builder(&cam)
        .position([0.0, 2.0, -5.0])
        .target([0.0, 0.0, 0.0])
        .build();

    while window.update() && !window.input.hit(three::KEY_ESCAPE) {
        controls.update(&window.input);
        window.render(&cam);
    }
}
<commit_msg>Able to get STL rendered<commit_after>extern crate three;
extern crate mint;
extern crate froggy;

use std::env;
use three::{Geometry, Object};
use mint::Point3;
use froggy::WeakPointer;

fn main() {
    let mut args = env::args();
    let obj_path = concat!(env!("CARGO_MANIFEST_DIR"), "/test_data/sample.stl");
    let path = args.nth(1).unwrap_or(obj_path.into());
    let mut vertices = vec!();

    match stlv::parser::load_file(path.as_str()) {
        Ok(model) => {
            for triangle in (*model).iter() {
                let stl_vertices = triangle.vertices();
                vertices.push(Point3 {
                    x: stl_vertices[0].get_x(),
                    y: stl_vertices[0].get_y(),
                    z: stl_vertices[0].get_z(),
                });
                vertices.push(Point3 {
                    x: stl_vertices[1].get_x(),
                    y: stl_vertices[1].get_y(),
                    z: stl_vertices[1].get_z(),
                });
                vertices.push(Point3 {
                    x: stl_vertices[2].get_x(),
                    y: stl_vertices[2].get_y(),
                    z: stl_vertices[2].get_z(),
                });
            }
        }
        _ => panic!("Failed to parse the STL file {}", path),
    }

    let geometry = Geometry::with_vertices(vertices);

    // Upload the triangle data to the GPU.
    let mut window = three::Window::new("Loading STL...");

    // Create multiple meshes with the same GPU data and material.
    let material = three::material::Basic {
        color: 0xFFFF00,
        map: None,
    };

    let mesh = window.factory.mesh(geometry, material);
    window.scene.add(&mesh);

    let cam = window.factory.perspective_camera(60.0, 1.0 .. 1000.0);
    let mut controls = three::controls::Orbit::builder(&cam)
        .position([0.0, 2.0, -5.0])
        .target([0.0, 0.0, 0.0])
        .build();

    let dir_light = window.factory.directional_light(0xffffff, 0.9);
    dir_light.look_at([15.0, 35.0, 35.0], [0.0, 0.0, 2.0], None);
    window.scene.add(&dir_light);

    while window.update() && !window.input.hit(three::KEY_ESCAPE) {
        controls.update(&window.input);
        window.render(&cam);
    }
}
<|endoftext|>


<commit_before>extern crate deeplearn;
extern crate matrix;

use deeplearn::Graph;
use deeplearn::op::{Add, MatMul, Mse, Relu};

fn main() {
    let ctx = matrix::Context::new();

    // Setup the graph
    let mut graph = Graph::new();

    // Input
    let a = graph.add_variable(&ctx, (5, 2));
    // Layer 1
    let l1_w = graph.add_variable(&ctx, (2, 3));
    let l1_mat_mul = graph.add_node(&ctx,
                                    Box::new(MatMul::new(&ctx, (5, 2), (2, 3))),
                                    vec![a, l1_w],
                                    &[(5, 3)]);
    let l1_mat_mul_out = l1_mat_mul.get(&graph).outputs[0];
    let l1_b = graph.add_variable(&ctx, (1, 3));
    let l1_fc = graph.add_node(&ctx,
                               Box::new(Add::new(0)),
                               vec![l1_mat_mul_out, l1_b],
                               &[(5, 3)]);
    let l1_fc_out = l1_fc.get(&graph).outputs[0];
    let l1_relu = graph.add_node(&ctx,
                                 Box::new(Relu::new()),
                                 vec![l1_fc_out],
                                 &[(5, 3)]);
    let l1_relu_out = l1_relu.get(&graph).outputs[0];
    // Layer 2
    let l2_w = graph.add_variable(&ctx, (3, 1));
    let l2_mat_mul = graph.add_node(&ctx,
                                    Box::new(MatMul::new(&ctx, (5, 3), (3, 1))),
                                    vec![l1_relu_out, l2_w],
                                    &[(5, 1)]);
    let l2_mat_mul_out = l2_mat_mul.get(&graph).outputs[0];
    let l2_b = graph.add_variable(&ctx, (5, 1));
    let l2_fc = graph.add_node(&ctx,
                               Box::new(Add::new(0)),
                               vec![l2_mat_mul_out, l2_b],
                               &[(5, 1)]);
    let l2_fc_out = l2_fc.get(&graph).outputs[0];
    let l2_relu = graph.add_node(&ctx,
                                 Box::new(Relu::new()),
                                 vec![l2_fc_out],
                                 &[(5, 1)]);
    let l2_relu_out = l2_relu.get(&graph).outputs[0];
    // Loss
    let train_out = graph.add_variable(&ctx, (5, 1));
    let loss = graph.add_node(&ctx,
                              Box::new(Mse::new()),
                              vec![l2_relu_out, train_out],
                              &[(1, 1)]);
    let loss_out = loss.get(&graph).outputs[0];
    let loss_d = graph.add_gradient(&ctx, loss, 0);

    // Send some input data
    let a_cpu = matrix::Matrix::from_vec(5, 2, vec![1.0, 0.0,
                                                    0.0, 1.0,
                                                    0.0, 0.0,
                                                    1.0, 1.0,
                                                    0.5, 0.0]);
    let train_out_cpu = matrix::Matrix::from_vec(5, 1, vec![1.0, 1.0, 0.0, 0.0, 0.5]);
    let l1_w_cpu = matrix::Matrix::from_vec(2, 3, vec![1.0, 0.3, 0.0,
                                                       0.0, 0.8, 0.6]);
    let l1_b_cpu = matrix::Matrix::from_vec(1, 3, vec![0.3, -0.5, 0.1]);
    let l2_w_cpu = matrix::Matrix::from_vec(3, 1, vec![1.0, 0.5, 1.0]);
    let l2_b_cpu = matrix::Matrix::from_vec(1, 1, vec![0.0]);
    let loss_d_cpu = matrix::Matrix::from_vec(1, 1, vec![-0.1]);
    a.get(&graph).set(&ctx, &a_cpu);
    train_out.get(&graph).set(&ctx, &train_out_cpu);
    l1_w.get(&graph).set(&ctx, &l1_w_cpu);
    //l1_b.get(&graph).set(&ctx, &l1_b_cpu);
    l2_w.get(&graph).set(&ctx, &l2_w_cpu);
    //l2_b.get(&graph).set(&ctx, &l2_b_cpu);
    loss_d.get(&graph).set(&ctx, &loss_d_cpu);

    // Run/Train the network
    for epoch in 0..1000 {
        graph.run(&ctx);
        let out = l2_relu_out.get(&graph).get(&ctx);
        let out_d = l2_relu.get(&graph)
                           .out_grad[0]
                           .gradient()
                           .get(&graph)
                           .get(&ctx);
        let l = loss_out.get(&graph).get(&ctx);
        let l1_w_d = graph.get_input_gradient(l1_w).unwrap().get(&graph);
        let l2_w_d = graph.get_input_gradient(l1_w).unwrap().get(&graph);
        l1_w.get(&graph).add(&ctx, -1, &*l1_w_d, &*l1_w.get(&graph));
        l2_w.get(&graph).add(&ctx, -1, &*l2_w_d, &*l2_w.get(&graph));
        if epoch % 100 == 0 {
            println!("===================");
            println!("Epoch: {}", epoch);
            println!("out = {:?}", out);
            println!("out_d = {:?}", out_d);
            println!("loss = {:?}", l);
            println!("l1_w = {:?}", l1_w.get(&graph).get(&ctx));
            println!("l2_w = {:?}", l2_w.get(&graph).get(&ctx));
        }
    }
}
<commit_msg>Played with xor model a bit<commit_after>extern crate deeplearn;
extern crate matrix;

use deeplearn::Graph;
use deeplearn::op::{Add, MatMul, Mse, Relu};

fn main() {
    let ctx = matrix::Context::new();

    // Setup the graph
    let mut graph = Graph::new();

    // Input
    let a = graph.add_variable(&ctx, (5, 2));
    // Layer 1
    let l1_w = graph.add_variable(&ctx, (2, 3));
    let l1_mat_mul = graph.add_node(&ctx,
                                    Box::new(MatMul::new(&ctx, (5, 2), (2, 3))),
                                    vec![a, l1_w],
                                    &[(5, 3)]);
    let l1_mat_mul_out = l1_mat_mul.get(&graph).outputs[0];
    let l1_b = graph.add_variable(&ctx, (1, 3));
    let l1_fc = graph.add_node(&ctx,
                               Box::new(Add::new(0)),
                               vec![l1_mat_mul_out, l1_b],
                               &[(5, 3)]);
    let l1_fc_out = l1_fc.get(&graph).outputs[0];
    let l1_relu = graph.add_node(&ctx,
                                 Box::new(Relu::new()),
                                 vec![l1_fc_out],
                                 &[(5, 3)]);
    let l1_relu_out = l1_relu.get(&graph).outputs[0];
    // Layer 2
    let l2_w = graph.add_variable(&ctx, (3, 1));
    let l2_mat_mul = graph.add_node(&ctx,
                                    Box::new(MatMul::new(&ctx, (5, 3), (3, 1))),
                                    vec![l1_relu_out, l2_w],
                                    &[(5, 1)]);
    let l2_mat_mul_out = l2_mat_mul.get(&graph).outputs[0];
    let l2_b = graph.add_variable(&ctx, (1, 1));
    let l2_fc = graph.add_node(&ctx,
                               Box::new(Add::new(0)),
                               vec![l2_mat_mul_out, l2_b],
                               &[(5, 1)]);
    let l2_fc_out = l2_fc.get(&graph).outputs[0];
    let l2_relu = graph.add_node(&ctx,
                                 Box::new(Relu::new()),
                                 vec![l2_fc_out],
                                 &[(5, 1)]);
    let l2_relu_out = l2_relu.get(&graph).outputs[0];
    // Loss
    let train_out = graph.add_variable(&ctx, (5, 1));
    let loss = graph.add_node(&ctx,
                              Box::new(Mse::new()),
                              vec![l2_relu_out, train_out],
                              &[(1, 1)]);
    let loss_out = loss.get(&graph).outputs[0];
    let loss_d = graph.add_gradient(&ctx, loss, 0);

    // Send some input data
    let a1_cpu = matrix::Matrix::from_vec(5, 2, vec![1.0, 0.0,
                                                     0.0, 1.0,
                                                     1.0, 0.0,
                                                     0.0, 1.0,
                                                     0.5, 0.0]);
    let a2_cpu = matrix::Matrix::from_vec(5, 2, vec![1.0, 1.0,
                                                     1.0, 1.0,
                                                     0.0, 0.0,
                                                     0.0, 0.0,
                                                     0.5, 0.5]);
    let train_out1_cpu = matrix::Matrix::from_vec(5, 1, vec![1.0, 1.0, 1.0, 1.0, 0.5]);
    let train_out2_cpu = matrix::Matrix::from_vec(5, 1, vec![0.0, 0.0, 0.0, 0.0, 0.0]);
    let l1_w_cpu = matrix::Matrix::from_vec(2, 3, vec![1.0, 0.3, 0.0,
                                                       0.0, 0.8, 0.6]);
    let l1_b_cpu = matrix::Matrix::from_vec(1, 3, vec![0.3, -0.5, 0.1]);
    let l2_w_cpu = matrix::Matrix::from_vec(3, 1, vec![1.0, 0.5, 1.0]);
    let l2_b_cpu = matrix::Matrix::from_vec(1, 1, vec![0.2]);
    let loss_d_cpu = matrix::Matrix::from_vec(1, 1, vec![-0.1]);
    l1_w.get(&graph).set(&ctx, &l1_w_cpu);
    l1_b.get(&graph).set(&ctx, &l1_b_cpu);
    l2_w.get(&graph).set(&ctx, &l2_w_cpu);
    l2_b.get(&graph).set(&ctx, &l2_b_cpu);
    loss_d.get(&graph).set(&ctx, &loss_d_cpu);

    // Run/Train the network
    for epoch in 0..1000 {
        if epoch % 2 == 0 {
            a.get(&graph).set(&ctx, &a1_cpu);
            train_out.get(&graph).set(&ctx, &train_out1_cpu);
        } else {
            a.get(&graph).set(&ctx, &a2_cpu);
            train_out.get(&graph).set(&ctx, &train_out2_cpu);
        }
        graph.run(&ctx);
        let out = l2_relu_out.get(&graph).get(&ctx);
        let out_d = l2_relu.get(&graph)
                           .out_grad[0]
                           .gradient()
                           .get(&graph)
                           .get(&ctx);
        let l = loss_out.get(&graph).get(&ctx);
        let l1_w_d = graph.get_input_gradient(l1_w).unwrap().get(&graph);
        let l2_w_d = graph.get_input_gradient(l1_w).unwrap().get(&graph);
        l1_w.get(&graph).add(&ctx, -1, &*l1_w_d, &*l1_w.get(&graph));
        l2_w.get(&graph).add(&ctx, -1, &*l2_w_d, &*l2_w.get(&graph));
        if epoch % 100 == 0 || epoch % 100 == 1 {
            println!("===================");
            println!("Epoch: {}", epoch);
            println!("out = {:?}", out);
            println!("out_d = {:?}", out_d);
            println!("loss = {:?}", l);
            println!("l1_w = {:?}", l1_w.get(&graph).get(&ctx));
            println!("l1_b = {:?}", l1_b.get(&graph).get(&ctx));
            println!("l2_w = {:?}", l2_w.get(&graph).get(&ctx));
            println!("l2_b = {:?}", l2_b.get(&graph).get(&ctx));
        }
    }
}
<|endoftext|>


<commit_before>#![feature(core)]
extern crate iron;
extern crate time;

use iron::prelude::*;
use iron::{Handler, BeforeMiddleware};
use iron::status;

use std::error::Error;
use std::fmt::{self, Debug};

struct ErrorHandler;
struct ErrorProducer;

#[derive(Debug)]
struct StringError(String);

impl fmt::Display for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

impl Error for StringError {
    fn description(&self) -> &str { &*self.0 }
}

impl Handler for ErrorHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        Ok(Response::new())
    }
}

impl BeforeMiddleware for ErrorProducer {
    fn before(&self, _: &mut Request) -> IronResult<()> {
        Err(IronError::new(StringError("Error".to_string()), status::Ok))
    }
}

fn main() {
    // Handler is attached here.
    let mut chain = Chain::new(ErrorHandler);

    // Link our error maker.
    chain.link_before(ErrorProducer);

    Iron::new(chain).http("localhost:3000").unwrap();
}

<commit_msg>(fix) Remove feature(core) for the latest rust nightly.<commit_after>extern crate iron;
extern crate time;

use iron::prelude::*;
use iron::{Handler, BeforeMiddleware};
use iron::status;

use std::error::Error;
use std::fmt::{self, Debug};

struct ErrorHandler;
struct ErrorProducer;

#[derive(Debug)]
struct StringError(String);

impl fmt::Display for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

impl Error for StringError {
    fn description(&self) -> &str { &*self.0 }
}

impl Handler for ErrorHandler {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        Ok(Response::new())
    }
}

impl BeforeMiddleware for ErrorProducer {
    fn before(&self, _: &mut Request) -> IronResult<()> {
        Err(IronError::new(StringError("Error".to_string()), status::Ok))
    }
}

fn main() {
    // Handler is attached here.
    let mut chain = Chain::new(ErrorHandler);

    // Link our error maker.
    chain.link_before(ErrorProducer);

    Iron::new(chain).http("localhost:3000").unwrap();
}

<|endoftext|>