<commit_before>//! A container for a series of audio devices.
//!
//! A chain can be used when a single series of audio devices passes its output
//! to the input of the next device. It is initialized from a single starting
//! device that will receive no input, and ends in a device who's output is
//! ignored.
//!
//!
//! # Example
//! The following will pass microphone input through a delay unit, then out to
//! the speaker:
//!
//! ```
//! # // this example uses tick_forever(), so we wrap it in a function that gets
//! # // compiled by not run by doctest
//! # fn dummy() {
//! use oxcable::delay::Delay;
//! use oxcable::chain::{DeviceChain, Tick};
//! use oxcable::io::audio::AudioEngine;
//!
//! let engine = AudioEngine::with_buffer_size(256).unwrap();
//! let mut chain = DeviceChain::from(
//!     engine.default_input(1).unwrap()
//! ).into(
//!     Delay::new(1.0, 0.5, 0.5, 1)
//! ).into(
//!     engine.default_output(1).unwrap()
//! );
//! chain.tick_forever();
//! # }
//! ```

use types::{AudioDevice, Sample, Time};
pub use tick::Tick;

/// A container for a series of audio devices.
pub struct DeviceChain {
    devices: Vec<AudioNode>,
    time: Time
}

impl DeviceChain {
    /// Creates a new chain that starts from the provided device. This device
    /// will receive no inputs.
    pub fn from<D>(device: D) -> Self where D: 'static+AudioDevice {
        DeviceChain { devices: vec![AudioNode::new(device)], time: 0 }
    }

    /// Appends the provided device to the end of the chain. This device will be
    /// passed the output of the last device as input. This method returns the
    /// same chain it was passed.
    pub fn into<D>(mut self, device: D) -> Self where D: 'static+AudioDevice {
        if self.devices[self.devices.len()-1].outputs.len() != device.num_inputs() {
            panic!("DeviceChain: number of outputs must match number of inputs");
        }
        self.devices.push(AudioNode::new(device));
        self
    }

    /// Fetches the last output frame from the end of the chain.
    pub fn get_output(&self) -> Vec<Sample> {
        self.devices[self.devices.len()-1].outputs.clone()
    }
}

impl Tick for DeviceChain {
    fn tick(&mut self) {
        self.devices[0].tick(self.time, &[0.0;0]);
        for i in 1..self.devices.len() {
            let inputs = self.devices[i-1].outputs.clone();
            self.devices[i].tick(self.time, &inputs);
        }
        self.time += 1;
    }
}

/// Wrap an audio device behind a pointer, and provide an allocated buffer to
/// contain its output.
struct AudioNode {
    device: Box<AudioDevice>,
    outputs: Vec<Sample>
}

impl AudioNode {
    /// Wraps the provided audio device in a new node and allocate its output
    /// buffer.
    fn new<D>(device: D) -> AudioNode where D: 'static+AudioDevice {
        let n = device.num_outputs();
        AudioNode {
            device: Box::new(device),
            outputs: vec![0.0; n]
        }
    }

    /// Ticks the device one time step.
    ///
    /// `inputs` should be the output of the previous device.
    fn tick(&mut self, t: Time, inputs: &[Sample]) {
        self.device.tick(t, inputs, &mut self.outputs);
    }
}
<commit_msg>Tweak chain IO to use slices<commit_after>//! A container for a series of audio devices.
//!
//! A chain can be used when a single series of audio devices passes its output
//! to the input of the next device. It is initialized from a single starting
//! device that will receive no input, and ends in a device who's output is
//! ignored.
//!
//!
//! # Example
//! The following will pass microphone input through a delay unit, then out to
//! the speaker:
//!
//! ```
//! # // this example uses tick_forever(), so we wrap it in a function that gets
//! # // compiled by not run by doctest
//! # fn dummy() {
//! use oxcable::delay::Delay;
//! use oxcable::chain::{DeviceChain, Tick};
//! use oxcable::io::audio::AudioEngine;
//!
//! let engine = AudioEngine::with_buffer_size(256).unwrap();
//! let mut chain = DeviceChain::from(
//!     engine.default_input(1).unwrap()
//! ).into(
//!     Delay::new(1.0, 0.5, 0.5, 1)
//! ).into(
//!     engine.default_output(1).unwrap()
//! );
//! chain.tick_forever();
//! # }
//! ```

use types::{AudioDevice, Sample, Time};
pub use tick::Tick;

/// A container for a series of audio devices.
pub struct DeviceChain {
    inputs: Vec<Sample>,
    devices: Vec<AudioNode>,
    time: Time
}

impl DeviceChain {
    /// Creates a new chain that starts from the provided device. This device
    /// will receive no inputs unless they are manually supplied using
    /// DeviceChain::get_input.
    pub fn from<D>(device: D) -> Self where D: 'static+AudioDevice {
        DeviceChain {
            inputs: vec![0.0; device.num_inputs()],
            devices: vec![AudioNode::new(device)],
            time: 0
        }
    }

    /// Appends the provided device to the end of the chain. This device will be
    /// passed the output of the last device as input. This method returns the
    /// same chain it was passed.
    pub fn into<D>(mut self, device: D) -> Self where D: 'static+AudioDevice {
        if self.devices[self.devices.len()-1].outputs.len() != device.num_inputs() {
            panic!("DeviceChain: number of outputs must match number of inputs");
        }
        self.devices.push(AudioNode::new(device));
        self
    }

    /// Return a mutable slice to the input of the first device in the chain.
    ///
    /// These inputs never get overwritten, so if you are supplying input you
    /// must manually zero the buffer again.
    pub fn get_input(&mut self) -> &mut[Sample] {
        &mut self.inputs
    }

    /// Returns a slice to the output of the last device in the chain.
    pub fn get_output(&self) -> &[Sample] {
        &self.devices[self.devices.len()-1].outputs
    }
}

impl Tick for DeviceChain {
    fn tick(&mut self) {
        self.devices[0].tick(self.time, &self.inputs);
        for i in 1..self.devices.len() {
            let inputs = self.devices[i-1].outputs.clone();
            self.devices[i].tick(self.time, &inputs);
        }
        self.time += 1;
    }
}

/// Wrap an audio device behind a pointer, and provide an allocated buffer to
/// contain its output.
struct AudioNode {
    device: Box<AudioDevice>,
    outputs: Vec<Sample>
}

impl AudioNode {
    /// Wraps the provided audio device in a new node and allocate its output
    /// buffer.
    fn new<D>(device: D) -> AudioNode where D: 'static+AudioDevice {
        let n = device.num_outputs();
        AudioNode {
            device: Box::new(device),
            outputs: vec![0.0; n]
        }
    }

    /// Ticks the device one time step.
    ///
    /// `inputs` should be the output of the previous device.
    fn tick(&mut self, t: Time, inputs: &[Sample]) {
        self.device.tick(t, inputs, &mut self.outputs);
    }
}
<|endoftext|>


<commit_before>
use syntax::ast;
use syntax::ast::{MetaItemKind,NestedMetaItemKind};
use rustc::hir::def_id::DefId;
use rustc::hir::def;
use syntax::codemap::Span;
use rustc::lint::{self, LintContext, LintPass, LateLintPass, LintArray};
use rustc::ty::{self, TyCtxt};
use rustc::hir;

declare_lint!(NOT_TAGGED_SAFE, Warn, "Warn about use of non-tagged methods within tagged function");

#[derive(Default)]
pub struct Pass
{
    visit_stack: Vec<ast::NodeId>,
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NOT_TAGGED_SAFE)
    }
}

impl<'a,'b> LateLintPass<'a,'b> for Pass {
    fn check_fn(&mut self, cx: &lint::LateContext, _kind: hir::intravisit::FnKind, _decl: &hir::FnDecl, body: &hir::Body, _: Span, id: ast::NodeId) {
        let attrs = cx.tcx.map.attrs(id);

        // If this function is tagged with a particular safety, store
        {
            let mut lh = ::database::CACHE.write().unwrap();
            for tag_name in get_tags(attrs, "is_safe")
            {
                let tag = lh.get_tag_or_add(&tag_name.as_str());
                lh.mark(id, tag,  true);
            }
            for tag_name in get_tags(attrs, "not_safe")
            {
                let tag = lh.get_tag_or_add(&tag_name.as_str());
                lh.mark(id, tag,  false);
            }
        }

        // For each required safety, check
        for tag_name in get_tags(attrs, "req_safe")
        {
            let ty_tag = {
                let mut lh = ::database::CACHE.write().unwrap();
                let tag = lh.get_tag_or_add(&tag_name.as_str());
                //let tag = if let Some(v) = lh.get_tag_opt(&tag_name.as_str()) { v } else { error!("Tag {} unknown", ty_name);  continue; };
                lh.mark(id, tag,  true);
                tag
                };

            // Search body for calls to non safe methods
            let mut v = Visitor {
                    pass: self, cx: cx, tag: ty_tag,
                    cb: |span| {
                            cx.span_lint(NOT_TAGGED_SAFE, *span,
                                &format!("Calling {0}-unsafe method from a #[req_safe({0})] method", tag_name)[..]
                                );
                        },
                    };
            debug!("Method {:?} is marked safe '{}'", id, tag_name);
            hir::intravisit::walk_body(&mut v, body);
        }

        // TODO: For all known safeties (that aren't already set) populate.
        // - Requires knowing all safeties (which we don't, ... yet)
    }
}

impl Pass
{
    fn fill_cache_for(&mut self, tcx: &TyCtxt, node_id: ast::NodeId)
    {
        debug!("Filling cache for node {:?}", node_id);
        let attrs = tcx.map.attrs(node_id);
        let mut lh = ::database::CACHE.write().unwrap();
        for tag_name in Iterator::chain( get_tags(attrs, "is_safe"), get_tags(attrs, "req_safe") )
        {
            debug!("#[is_safe/req_safe] {} - {}", tag_name, node_id);
            let tag = lh.get_tag_or_add(&tag_name.as_str());
            lh.mark(node_id, tag,  true);
        }
        for tag_name in get_tags(attrs, "not_safe")
        {
            debug!("#[not_safe] {} - {}", tag_name, node_id);
            let tag = lh.get_tag_or_add(&tag_name.as_str());
            lh.mark(node_id, tag,  false);
        }
    }

    /// Recursively check that the provided function is either safe or unsafe.
    // Used to avoid excessive annotating
    fn recurse_fcn_body(&mut self, cx: &lint::LateContext, node_id: ast::NodeId, tag: ::database::Tag) -> bool
    {
        // and apply a visitor to all
        match cx.tcx.map.get(node_id)
        {
        hir::map::NodeItem(i) =>
            match i.node {
            hir::ItemFn(_, _, _, _, _, ref body) => {
                // Enumerate this function's code, recursively checking for a call to an unsafe method
                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, cx: cx, tag: tag,
                        cb: |_| { is_safe = false; }
                        };
                    hir::intravisit::walk_body(&mut v, cx.tcx.map.body(*body));
                }
                is_safe
                },
            ref v @ _ => {
                error!("Node ID {} points to a non-function item {:?}", node_id, v);
                true
                },
            },
        hir::map::NodeImplItem(i) =>
            match i.node {
            hir::ImplItemKind::Method(_, ref body) => {

                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, cx: cx, tag: tag,
                        cb: |_| { is_safe = false; }
                        };
                    hir::intravisit::walk_body(&mut v, cx.tcx.map.body(*body));
                }
                is_safe
                },
            _ => true,
            },
        //hir::map::NodeForeignItem(i) =>
        //    if Self::check_for_marker(tcx, i.id, "tag_safe", name) {
        //        true
        //    }
        //    else if Self::check_for_marker(tcx, i.id, "tag_unsafe", name) {
        //        false
        //    }
        //    else {
        //        unknown_assume
        //    },
        ref v @ _ => {
            error!("Node ID {} points to non-item {:?}", node_id, v);
            true
            }
        }
    }

    /// Locate a #[tag_safe(<name>)] attribute on the passed item
    pub fn method_is_safe(&mut self, cx: &lint::LateContext, id: DefId, tag: ::database::Tag) -> bool
    {
        if ! id.is_local()
        {
            // TODO: Get the entry from the crate cache
            if let Some(v) = ::database::CACHE.read().unwrap().get_extern(&cx.tcx,id.krate, id.index, tag) {
                debug!("{:?} - {} (extern cached)", id, v);
                v
            }
            else {
                debug!("{:?} - {} (extern assumed)", id, true);
                true
            }
        }
        else
        {
            let node_id = cx.tcx.map.as_local_node_id(id).expect("Unable to locate node");
            let mut local_opt = ::database::CACHE.read().unwrap().get_local(node_id, tag);
            // NOTE: This only fires once (ideally)
            if local_opt.is_none() {
                self.fill_cache_for(&cx.tcx, node_id);
                local_opt = ::database::CACHE.read().unwrap().get_local(node_id, tag);
            }
            if let Some(v) = local_opt {
                debug!("{} - {} (cached)", node_id, v);
                v
            }
            else {
                // If this node is currently being checked, assume it's valid.
                // TODO: This can lead to a false positive being stored.
                if self.visit_stack.iter().position(|x| *x == node_id).is_some() {
                    warn!("Recursion, assuming true");
                    true
                }
                else {
                    self.visit_stack.push(node_id);
                    let rv = self.recurse_fcn_body(cx, node_id, tag);
                    self.visit_stack.pop();

                    debug!("{} - {} (recursed)", node_id, rv);
                    ::database::CACHE.write().unwrap().mark(node_id, tag,  rv);
                    rv
                }
            }
        }
    }
}

struct Visitor<'a, 'tcx: 'a, F: FnMut(&Span) + 'a>
{
    pass: &'a mut Pass,
	cx: &'a lint::LateContext<'a,'tcx>,
    tag: ::database::Tag,
    cb: F,
}

impl<'a, 'tcx: 'a, F: FnMut(&Span)> hir::intravisit::Visitor<'a> for Visitor<'a, 'tcx, F>
{
	fn nested_visit_map<'this>(&'this mut self) -> hir::intravisit::NestedVisitorMap<'this, 'a> {
		hir::intravisit::NestedVisitorMap::None
	}

    // Locate function/method calls in a code block
    fn visit_expr(&mut self, ex: &'a hir::Expr) {
        debug!("visit node - {:?}", ex);
        match ex.node
        {
        // Call expressions - check that it's a path call
        hir::ExprCall(ref fcn, ..) =>
			match fcn.node
			{
			hir::ExprPath(ref qp, ..) =>
				match self.cx.tables.qpath_def(qp, fcn.id)
				{
				def::Def::Fn(did) | def::Def::Method(did) =>
					// Check for a safety tag
					if !self.pass.method_is_safe(self.cx, did, self.tag)
					{
						(self.cb)(&ex.span);
					}
					else {
						debug!("Safe call {:?}", ex);
					},
				_ => {
					info!("Call ExprPath with an unknown Def type");
					},
				},
			_ => {
				info!("Call without ExprPath");
				},
			},

        // Method call expressions - get the relevant method
        hir::ExprMethodCall(ref _id, ref _tys, ref _exprs) =>
			match self.cx.tables.method_map.get( &ty::MethodCall::expr(ex.id) )
			{
			Some(callee) => {
                let id = callee.def_id;

				// Check for a safety tag
				if !self.pass.method_is_safe(self.cx, id, self.tag) {
					(self.cb)(&ex.span);
				}
				},
			None => info!("ExprMethodCall with unknown callee"),
			},

        // Ignore any other type of node
        _ => {},
        }
        hir::intravisit::walk_expr(self, ex);
    }
}

fn get_tags<'a>(meta_items: &'a [ast::Attribute], attr_name: &'a str) -> impl Iterator<Item=::syntax::symbol::Symbol>+'a {
    meta_items.iter()
        .filter(move |attr| attr.value.name == attr_name)
        .flat_map(|attr|
            if let MetaItemKind::List(ref v) = attr.value.node {
                v.iter()
            }
            else {
                panic!("");
            }
            )
        .filter_map(|tag_meta|
            if let NestedMetaItemKind::MetaItem(ref ptr) = tag_meta.node {
                if let MetaItemKind::Word = ptr.node {
                    Some(ptr.name)
                }
                else {
                    warn!("");
                    None
                }
            }
            else {
                warn!("");
                None
            }
            )
}
<commit_msg>Fix nighly churn<commit_after>
use syntax::ast;
use syntax::ast::{MetaItemKind,NestedMetaItemKind};
use rustc::hir::def_id::DefId;
use rustc::hir::def;
use syntax::codemap::Span;
use rustc::lint::{self, LintContext, LintPass, LateLintPass, LintArray};
use rustc::ty::{self, TyCtxt};
use rustc::hir;

declare_lint!(NOT_TAGGED_SAFE, Warn, "Warn about use of non-tagged methods within tagged function");

#[derive(Default)]
pub struct Pass
{
    visit_stack: Vec<ast::NodeId>,
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NOT_TAGGED_SAFE)
    }
}

impl<'a,'b> LateLintPass<'a,'b> for Pass {
    fn check_fn(&mut self, cx: &lint::LateContext, _kind: hir::intravisit::FnKind, _decl: &hir::FnDecl, body: &hir::Body, _: Span, id: ast::NodeId) {
        let attrs = cx.tcx.hir.attrs(id);

        // If this function is tagged with a particular safety, store
        {
            let mut lh = ::database::CACHE.write().unwrap();
            for tag_name in get_tags(attrs, "is_safe")
            {
                let tag = lh.get_tag_or_add(&tag_name.as_str());
                lh.mark(id, tag,  true);
            }
            for tag_name in get_tags(attrs, "not_safe")
            {
                let tag = lh.get_tag_or_add(&tag_name.as_str());
                lh.mark(id, tag,  false);
            }
        }

        // For each required safety, check
        for tag_name in get_tags(attrs, "req_safe")
        {
            let ty_tag = {
                let mut lh = ::database::CACHE.write().unwrap();
                let tag = lh.get_tag_or_add(&tag_name.as_str());
                //let tag = if let Some(v) = lh.get_tag_opt(&tag_name.as_str()) { v } else { error!("Tag {} unknown", ty_name);  continue; };
                lh.mark(id, tag,  true);
                tag
                };

            // Search body for calls to non safe methods
            let mut v = Visitor {
                    pass: self, cx: cx, tag: ty_tag,
                    cb: |span| {
                            cx.span_lint(NOT_TAGGED_SAFE, *span,
                                &format!("Calling {0}-unsafe method from a #[req_safe({0})] method", tag_name)[..]
                                );
                        },
                    };
            debug!("Method {:?} is marked safe '{}'", id, tag_name);
            hir::intravisit::walk_body(&mut v, body);
        }

        // TODO: For all known safeties (that aren't already set) populate.
        // - Requires knowing all safeties (which we don't, ... yet)
    }
}

impl Pass
{
    fn fill_cache_for(&mut self, tcx: &TyCtxt, node_id: ast::NodeId)
    {
        debug!("Filling cache for node {:?}", node_id);
        let attrs = tcx.hir.attrs(node_id);
        let mut lh = ::database::CACHE.write().unwrap();
        for tag_name in Iterator::chain( get_tags(attrs, "is_safe"), get_tags(attrs, "req_safe") )
        {
            debug!("#[is_safe/req_safe] {} - {}", tag_name, node_id);
            let tag = lh.get_tag_or_add(&tag_name.as_str());
            lh.mark(node_id, tag,  true);
        }
        for tag_name in get_tags(attrs, "not_safe")
        {
            debug!("#[not_safe] {} - {}", tag_name, node_id);
            let tag = lh.get_tag_or_add(&tag_name.as_str());
            lh.mark(node_id, tag,  false);
        }
    }

    /// Recursively check that the provided function is either safe or unsafe.
    // Used to avoid excessive annotating
    fn recurse_fcn_body(&mut self, cx: &lint::LateContext, node_id: ast::NodeId, tag: ::database::Tag) -> bool
    {
        // and apply a visitor to all
        match cx.tcx.hir.get(node_id)
        {
        hir::map::NodeItem(i) =>
            match i.node {
            hir::ItemFn(_, _, _, _, _, ref body) => {
                // Enumerate this function's code, recursively checking for a call to an unsafe method
                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, cx: cx, tag: tag,
                        cb: |_| { is_safe = false; }
                        };
                    hir::intravisit::walk_body(&mut v, cx.tcx.hir.body(*body));
                }
                is_safe
                },
            ref v @ _ => {
                error!("Node ID {} points to a non-function item {:?}", node_id, v);
                true
                },
            },
        hir::map::NodeImplItem(i) =>
            match i.node {
            hir::ImplItemKind::Method(_, ref body) => {

                let mut is_safe = true;
                {
                    let mut v = Visitor {
                        pass: self, cx: cx, tag: tag,
                        cb: |_| { is_safe = false; }
                        };
                    hir::intravisit::walk_body(&mut v, cx.tcx.hir.body(*body));
                }
                is_safe
                },
            _ => true,
            },
        //hir::map::NodeForeignItem(i) =>
        //    if Self::check_for_marker(tcx, i.id, "tag_safe", name) {
        //        true
        //    }
        //    else if Self::check_for_marker(tcx, i.id, "tag_unsafe", name) {
        //        false
        //    }
        //    else {
        //        unknown_assume
        //    },
        ref v @ _ => {
            error!("Node ID {} points to non-item {:?}", node_id, v);
            true
            }
        }
    }

    /// Locate a #[tag_safe(<name>)] attribute on the passed item
    pub fn method_is_safe(&mut self, cx: &lint::LateContext, id: DefId, tag: ::database::Tag) -> bool
    {
        if ! id.is_local()
        {
            // TODO: Get the entry from the crate cache
            if let Some(v) = ::database::CACHE.read().unwrap().get_extern(&cx.tcx,id.krate, id.index, tag) {
                debug!("{:?} - {} (extern cached)", id, v);
                v
            }
            else {
                debug!("{:?} - {} (extern assumed)", id, true);
                true
            }
        }
        else
        {
            let node_id = cx.tcx.hir.as_local_node_id(id).expect("Unable to locate node");
            let mut local_opt = ::database::CACHE.read().unwrap().get_local(node_id, tag);
            // NOTE: This only fires once (ideally)
            if local_opt.is_none() {
                self.fill_cache_for(&cx.tcx, node_id);
                local_opt = ::database::CACHE.read().unwrap().get_local(node_id, tag);
            }
            if let Some(v) = local_opt {
                debug!("{} - {} (cached)", node_id, v);
                v
            }
            else {
                // If this node is currently being checked, assume it's valid.
                // TODO: This can lead to a false positive being stored.
                if self.visit_stack.iter().position(|x| *x == node_id).is_some() {
                    warn!("Recursion, assuming true");
                    true
                }
                else {
                    self.visit_stack.push(node_id);
                    let rv = self.recurse_fcn_body(cx, node_id, tag);
                    self.visit_stack.pop();

                    debug!("{} - {} (recursed)", node_id, rv);
                    ::database::CACHE.write().unwrap().mark(node_id, tag,  rv);
                    rv
                }
            }
        }
    }
}

struct Visitor<'a, 'tcx: 'a, F: FnMut(&Span) + 'a>
{
    pass: &'a mut Pass,
	cx: &'a lint::LateContext<'a,'tcx>,
    tag: ::database::Tag,
    cb: F,
}

impl<'a, 'tcx: 'a, F: FnMut(&Span)> hir::intravisit::Visitor<'a> for Visitor<'a, 'tcx, F>
{
	fn nested_visit_map<'this>(&'this mut self) -> hir::intravisit::NestedVisitorMap<'this, 'a> {
		hir::intravisit::NestedVisitorMap::None
	}

    // Locate function/method calls in a code block
    fn visit_expr(&mut self, ex: &'a hir::Expr) {
        debug!("visit node - {:?}", ex);
        match ex.node
        {
        // Call expressions - check that it's a path call
        hir::ExprCall(ref fcn, ..) =>
			match fcn.node
			{
			hir::ExprPath(ref qp, ..) =>
				match self.cx.tables.qpath_def(qp, fcn.id)
				{
				def::Def::Fn(did) | def::Def::Method(did) =>
					// Check for a safety tag
					if !self.pass.method_is_safe(self.cx, did, self.tag)
					{
						(self.cb)(&ex.span);
					}
					else {
						debug!("Safe call {:?}", ex);
					},
				_ => {
					info!("Call ExprPath with an unknown Def type");
					},
				},
			_ => {
				info!("Call without ExprPath");
				},
			},

        // Method call expressions - get the relevant method
        hir::ExprMethodCall(ref _id, ref _tys, ref _exprs) =>
			match self.cx.tables.method_map.get( &ty::MethodCall::expr(ex.id) )
			{
			Some(callee) => {
                let id = callee.def_id;

				// Check for a safety tag
				if !self.pass.method_is_safe(self.cx, id, self.tag) {
					(self.cb)(&ex.span);
				}
				},
			None => info!("ExprMethodCall with unknown callee"),
			},

        // Ignore any other type of node
        _ => {},
        }
        hir::intravisit::walk_expr(self, ex);
    }
}

fn get_tags<'a>(meta_items: &'a [ast::Attribute], attr_name: &'a str) -> impl Iterator<Item=::syntax::symbol::Symbol>+'a {
    meta_items.iter()
        .filter(move |attr| attr.value.name == attr_name)
        .flat_map(|attr|
            if let MetaItemKind::List(ref v) = attr.value.node {
                v.iter()
            }
            else {
                panic!("");
            }
            )
        .filter_map(|tag_meta|
            if let NestedMetaItemKind::MetaItem(ref ptr) = tag_meta.node {
                if let MetaItemKind::Word = ptr.node {
                    Some(ptr.name)
                }
                else {
                    warn!("");
                    None
                }
            }
            else {
                warn!("");
                None
            }
            )
}
<|endoftext|>


<commit_before>use linear::Vector3;

pub type Color = Vector3<f32>;
<commit_msg>Added ColorAlpha (RGBA).<commit_after>use linear::{Vector3, Vector4};

pub type Color = Vector3<f32>;
pub type ColorAlpha = Vector4<f32>;
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

#![crate_name="macro_platformtree"]
#![crate_type="dylib"]

#![feature(plugin_registrar, quote, managed_boxes)]

extern crate debug;
extern crate platformtree;
extern crate rustc;
extern crate serialize;
extern crate syntax;

use rustc::plugin::Registry;
use std::gc::{Gc, GC};
use syntax::ast;
use syntax::codemap::DUMMY_SP;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacResult, ItemModifier};
use syntax::ext::build::AstBuilder;
use syntax::owned_slice::OwnedSlice;
use syntax::print::pprust;
use syntax::util::small_vector::SmallVector;

use platformtree::parser::Parser;
use platformtree::builder::Builder;
use platformtree::builder::meta_args::ToTyHash;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
  reg.register_macro("platformtree", macro_platformtree);
  reg.register_macro("platformtree_verbose", macro_platformtree_verbose);
  reg.register_syntax_extension(syntax::parse::token::intern("zinc_task"),
      ItemModifier(macro_zinc_task));
}

pub fn macro_platformtree(cx: &mut ExtCtxt, _: Span, tts: &[ast::TokenTree])
    -> Box<MacResult> {
  let pt = Parser::new(cx, tts).parse_platformtree();
  let builder = Builder::build(cx, pt.unwrap());

  let items = builder.emit_items(cx);
  MacItems::new(items)
}

pub fn macro_platformtree_verbose(cx: &mut ExtCtxt, sp: Span,
    tts: &[ast::TokenTree]) -> Box<MacResult> {
  let result = macro_platformtree(cx, sp, tts);

  println!("Platform Tree dump:")
  for i in result.make_items().unwrap().as_slice().iter() {
    println!("{}", pprust::item_to_str(i.deref()));
  }

  result
}

fn macro_zinc_task(cx: &mut ExtCtxt, _: Span, _: Gc<ast::MetaItem>,
    it: Gc<ast::Item>) -> Gc<ast::Item> {
  match it.node {
    ast::ItemFn(decl, style, abi, _, block) => {
      let istr = syntax::parse::token::get_ident(it.ident);
      let fn_name = istr.get();
      let ty_params = platformtree::builder::meta_args::get_ty_params_for_task(cx, fn_name);

      let params = ty_params.iter().map(|ty| {
        cx.typaram(
            DUMMY_SP,
            cx.ident_of(ty.to_tyhash().as_slice()),
            ast::StaticSize,
            OwnedSlice::from_vec(vec!(cx.typarambound(
                cx.path(DUMMY_SP, ty.as_slice().split_str("::").map(|t| cx.ident_of(t)).collect())))),
            None)
      }).collect();

      let new_arg = cx.arg(DUMMY_SP, cx.ident_of("args"), cx.ty_rptr(
          DUMMY_SP,
          cx.ty_path(
              cx.path_all(
                  DUMMY_SP,
                  false,
                  ["pt".to_str(), fn_name.to_str() + "_args"].iter().map(|t| cx.ident_of(t.as_slice())).collect(),
                  vec!(),
                  ty_params.iter().map(|ty| {
                    cx.ty_path(cx.path_ident(DUMMY_SP, cx.ident_of(ty.to_tyhash().as_slice())), None)
                  }).collect()),
              None),
          None,
          ast::MutImmutable));
      let new_decl = box(GC) ast::FnDecl {
        inputs: vec!(new_arg),
        ..decl.deref().clone()
      };

      let new_generics = ast::Generics {
        lifetimes: vec!(),
        ty_params: OwnedSlice::from_vec(params),
      };
      let new_node = ast::ItemFn(new_decl, style, abi, new_generics, block);

      let i = box(GC) ast::Item {node: new_node, ..it.deref().clone() };
      println!("{}", pprust::item_to_str(i.deref()));
      i
    },
    _ => fail!(),
  }
}

pub struct MacItems {
  items: Vec<Gc<ast::Item>>
}

impl MacItems {
  pub fn new(items: Vec<Gc<ast::Item>>) -> Box<MacResult> {
    box MacItems { items: items } as Box<MacResult>
  }
}
impl MacResult for MacItems {
  fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
    Some(SmallVector::many(self.items.clone()))
  }
}
<commit_msg>Removed debug logging<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

#![crate_name="macro_platformtree"]
#![crate_type="dylib"]

#![feature(plugin_registrar, quote, managed_boxes)]

extern crate platformtree;
extern crate rustc;
extern crate serialize;
extern crate syntax;

use rustc::plugin::Registry;
use std::gc::{Gc, GC};
use syntax::ast;
use syntax::codemap::DUMMY_SP;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacResult, ItemModifier};
use syntax::ext::build::AstBuilder;
use syntax::owned_slice::OwnedSlice;
use syntax::print::pprust;
use syntax::util::small_vector::SmallVector;

use platformtree::parser::Parser;
use platformtree::builder::Builder;
use platformtree::builder::meta_args::ToTyHash;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
  reg.register_macro("platformtree", macro_platformtree);
  reg.register_macro("platformtree_verbose", macro_platformtree_verbose);
  reg.register_syntax_extension(syntax::parse::token::intern("zinc_task"),
      ItemModifier(macro_zinc_task));
}

pub fn macro_platformtree(cx: &mut ExtCtxt, _: Span, tts: &[ast::TokenTree])
    -> Box<MacResult> {
  let pt = Parser::new(cx, tts).parse_platformtree();
  let builder = Builder::build(cx, pt.unwrap());

  let items = builder.emit_items(cx);
  MacItems::new(items)
}

pub fn macro_platformtree_verbose(cx: &mut ExtCtxt, sp: Span,
    tts: &[ast::TokenTree]) -> Box<MacResult> {
  let result = macro_platformtree(cx, sp, tts);

  println!("Platform Tree dump:")
  for i in result.make_items().unwrap().as_slice().iter() {
    println!("{}", pprust::item_to_str(i.deref()));
  }

  result
}

fn macro_zinc_task(cx: &mut ExtCtxt, _: Span, _: Gc<ast::MetaItem>,
    it: Gc<ast::Item>) -> Gc<ast::Item> {
  match it.node {
    ast::ItemFn(decl, style, abi, _, block) => {
      let istr = syntax::parse::token::get_ident(it.ident);
      let fn_name = istr.get();
      let ty_params = platformtree::builder::meta_args::get_ty_params_for_task(cx, fn_name);

      let params = ty_params.iter().map(|ty| {
        cx.typaram(
            DUMMY_SP,
            cx.ident_of(ty.to_tyhash().as_slice()),
            ast::StaticSize,
            OwnedSlice::from_vec(vec!(cx.typarambound(
                cx.path(DUMMY_SP, ty.as_slice().split_str("::").map(|t| cx.ident_of(t)).collect())))),
            None)
      }).collect();

      let new_arg = cx.arg(DUMMY_SP, cx.ident_of("args"), cx.ty_rptr(
          DUMMY_SP,
          cx.ty_path(
              cx.path_all(
                  DUMMY_SP,
                  false,
                  ["pt".to_str(), fn_name.to_str() + "_args"].iter().map(|t| cx.ident_of(t.as_slice())).collect(),
                  vec!(),
                  ty_params.iter().map(|ty| {
                    cx.ty_path(cx.path_ident(DUMMY_SP, cx.ident_of(ty.to_tyhash().as_slice())), None)
                  }).collect()),
              None),
          None,
          ast::MutImmutable));
      let new_decl = box(GC) ast::FnDecl {
        inputs: vec!(new_arg),
        ..decl.deref().clone()
      };

      let new_generics = ast::Generics {
        lifetimes: vec!(),
        ty_params: OwnedSlice::from_vec(params),
      };
      let new_node = ast::ItemFn(new_decl, style, abi, new_generics, block);

      box(GC) ast::Item {node: new_node, ..it.deref().clone() }
    },
    _ => fail!(),
  }
}

pub struct MacItems {
  items: Vec<Gc<ast::Item>>
}

impl MacItems {
  pub fn new(items: Vec<Gc<ast::Item>>) -> Box<MacResult> {
    box MacItems { items: items } as Box<MacResult>
  }
}
impl MacResult for MacItems {
  fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
    Some(SmallVector::many(self.items.clone()))
  }
}
<|endoftext|>


<commit_before>extern crate fall;

use fall::Node;

pub use generator::Grammar;

mod parser;

mod generator;

use self::parser::grammar::*;

type Error = ();

pub fn parse(text: &str) -> Result<Grammar, Error> {
    let file = parser::parse(text.to_owned());
    let root = file.root();

    let nodes = root.children().single_of_type(NODES_DEF).ok_or(())?;
    let tokenizer = root.children().single_of_type(TOKENIZER_DEF).ok_or(())?;

    let node_types = nodes
        .children().many_of_type(IDENT)
        .map(|n| n.text().to_owned())
        .collect();

    let rules = tokenizer
        .children().many_of_type(RULE)
        .map(|rule| -> Result<(String, String), Error> {
            let id = rule.children().single_of_type(IDENT).ok_or(())?
                .text().to_owned();
            let pat = rule.children().single_of_type(STRING).ok_or(())?
                .text().to_owned();
            Ok((id, pat))
        })
        .collect::<Result<Vec<_>, Error>>()?;

    Ok(Grammar { node_types: node_types, tokenizer_rules: rules })
}
<commit_msg>Unused import<commit_after>extern crate fall;

pub use generator::Grammar;

mod parser;

mod generator;

use self::parser::grammar::*;

type Error = ();

pub fn parse(text: &str) -> Result<Grammar, Error> {
    let file = parser::parse(text.to_owned());
    let root = file.root();

    let nodes = root.children().single_of_type(NODES_DEF).ok_or(())?;
    let tokenizer = root.children().single_of_type(TOKENIZER_DEF).ok_or(())?;

    let node_types = nodes
        .children().many_of_type(IDENT)
        .map(|n| n.text().to_owned())
        .collect();

    let rules = tokenizer
        .children().many_of_type(RULE)
        .map(|rule| -> Result<(String, String), Error> {
            let id = rule.children().single_of_type(IDENT).ok_or(())?
                .text().to_owned();
            let pat = rule.children().single_of_type(STRING).ok_or(())?
                .text().to_owned();
            Ok((id, pat))
        })
        .collect::<Result<Vec<_>, Error>>()?;

    Ok(Grammar { node_types: node_types, tokenizer_rules: rules })
}
<|endoftext|>


<commit_before>#![feature(type_macros)]

#[macro_use]
extern crate nemo;
use nemo::*;
use nemo::session_types::*;
use nemo::peano::*;

#[test]
fn test_proto_macro() {
    use std::marker::PhantomData;

    type MyAlias = Recv<usize, End>;

    fn get<T>() -> PhantomData<T> { PhantomData }

    macro_rules! same {
        ($t1:ty = $t2:ty) => (
            {
                let _: PhantomData<$t1> = get::<$t2>();
            }
        )
    }

    // Send/Recv
    same!(Recv<usize, End> = proto!(Recv usize, End));
    same!(Send<usize, End> = proto!(Send usize, End));
    same!(Send<usize, Recv<u8, End>> = proto!(Send usize, Recv u8, End));
    same!(Recv<usize, Send<u8, End>> = proto!(Recv usize, Send u8, End));

    // Nest/Escape
    same!(Nest<Send<usize, Escape<Z>>> = proto!(
        loop {
            Send usize,
            continue 0
        }
    ));

    same!(Nest<Recv<usize, Nest<Send<usize, Escape<S<Z>>>>>> = proto!(
        loop {
            Recv usize,
            loop {
                Send usize,
                continue 1
            }
        }
    ));

    // Choose/Accept

    same!(Choose<Recv<usize, End>, Finally<End>> = proto!(
        Choose {
            {
                Recv usize,
                End
            },
            End
        }
    ));

    same!(
        Nest<
            Recv<usize,
                 Choose<
                    Recv<usize, Send<usize, Escape<Z>>>,
                    Choose<
                        Send<usize, End>,
                        Finally<
                            Nest<
                                Recv<usize,
                                     Choose<
                                        Escape<Z>,
                                        Finally<Escape<S<Z>>>
                                     >
                                >
                            >
                        >
                    >
                 >
            >
        >
     = proto!(
        loop {
            Recv usize,
            Choose {
                {
                    Recv usize,
                    Send usize,
                    continue 0
                },
                {
                    Send usize,
                    End
                },
                {
                    loop {
                        Recv usize,
                        Choose {
                            {continue 0},
                            {continue 1}
                        }
                    }
                }
            }
        }
    ));

    same!(
        Nest<
            Recv<usize,
                 Accept<
                    Recv<usize, Send<usize, Escape<Z>>>,
                    Accept<
                        Send<usize, End>,
                        Finally<
                            Nest<
                                Recv<usize,
                                     Accept<
                                        Escape<Z>,
                                        Finally<Escape<S<Z>>>
                                     >
                                >
                            >
                        >
                    >
                 >
            >
        >
     = proto!(
        loop {
            Recv usize,
            Accept {
                {
                    Recv usize,
                    Send usize,
                    continue 0
                },
                {
                    Send usize,
                    End
                },
                {
                    loop {
                        Recv usize,
                        Accept {
                            {continue 0},
                            {continue 1}
                        }
                    }
                }
            }
        }
    ));

    same!(Recv<usize, End> = proto!(goto MyAlias));
}

#[test]
fn choosing_protocol() {
    use nemo::channels::Blocking;

    struct MyProtocol;

    type SendString = Send<String, End>;
    type SendUsize = Send<usize, End>;
    type SendIsize = Send<isize, End>;
    type Orig = Choose<SendString, Choose<SendUsize, Finally<SendIsize>>>;

    type DualSendString = Recv<String, End>;
    type DualSendUsize = Recv<usize, End>;
    type DualSendIsize = Recv<isize, End>;
    type DualOrig = Accept<DualSendString, Accept<DualSendUsize, Finally<DualSendIsize>>>;

    impl Protocol for MyProtocol {
        type Initial = Orig;
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, Orig> for MyProtocol {
        fn with(this: Channel<Self, I, E, Orig>) -> Defer<Self, I> {
            this.choose::<SendIsize>().send(10).close()
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualOrig> for MyProtocol {
        fn with(this: Channel<Self, I, E, DualOrig>) -> Defer<Self, I> {
            this.accept().ok().unwrap()
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualSendString> for MyProtocol {
        fn with(_: Channel<Self, I, E, DualSendString>) -> Defer<Self, I> {
            panic!("should not have received a string..")
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualSendUsize> for MyProtocol {
        fn with(_: Channel<Self, I, E, DualSendUsize>) -> Defer<Self, I> {
            panic!("should not have received a usize..")
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualSendIsize> for MyProtocol {
        fn with(this: Channel<Self, I, E, DualSendIsize>) -> Defer<Self, I> {
            match this.recv() {
                Ok((msg, sess)) => {
                    assert_eq!(msg, 10);

                    sess.close()
                },
                Err(_) => {
                    panic!("expected to get a message...");
                }
            }
        }
    }

    let (client1, client2) = Blocking::new::<MyProtocol>(MyProtocol, MyProtocol);

    let mut client1 = client1.defer();
    let mut client2 = client2.defer();

    assert_eq!(false, client1.with()); // client1 chooses a protocol, sends 10, closes channel
    assert_eq!(false, client2.with()); // client2 accepts the protocol, handles it immediately, closes
}

#[test]
fn recursive_protocol() {
    use nemo::channels::Blocking;

    struct MyProtocol;

    type Orig = Nest<OrigEntered>;
    type OrigEntered = Send<usize, AwaitingNumber>;
    type AwaitingNumber = Recv<usize, Escape<Z>>;

    type DualOrig = Nest<DualOrigEntered>;
    type DualOrigEntered = Recv<usize, Send<usize, Escape<Z>>>;

    impl Protocol for MyProtocol {
        type Initial = Orig;
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, Orig> for MyProtocol {
        fn with(this: Channel<Self, I, E, Orig>) -> Defer<Self, I> {
            this.enter().defer()
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, (OrigEntered, E), OrigEntered> for MyProtocol {
        fn with(this: Channel<Self, I, (OrigEntered, E), OrigEntered>) -> Defer<Self, I> {
            this.send(10).defer()
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, (OrigEntered, E), AwaitingNumber> for MyProtocol {
        fn with(this: Channel<Self, I, (OrigEntered, E), AwaitingNumber>) -> Defer<Self, I> {
            match this.recv() {
                Ok((msg, this)) => {
                    assert_eq!(msg, 20);
                    this.pop().defer()
                },
                Err(_) => panic!("should have received a message")
            }
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, DualOrig> for MyProtocol {
        fn with(this: Channel<Self, I, E, DualOrig>) -> Defer<Self, I> {
            this.enter().defer()
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, (DualOrigEntered, E), DualOrigEntered> for MyProtocol {
        fn with(this: Channel<Self, I, (DualOrigEntered, E), DualOrigEntered>) -> Defer<Self, I> {
            match this.recv() {
                Ok((msg, this)) => {
                    assert_eq!(msg, 10);
                    this.send(20).pop().defer()
                },
                Err(_) => panic!("should have received a message")
            }
        }
    }

    let (client1, client2) = Blocking::new::<MyProtocol>(MyProtocol, MyProtocol);

    let mut client1 = client1.defer();
    let mut client2 = client2.defer();

    assert_eq!(true, client1.with()); // enters nesting
    assert_eq!(true, client1.with()); // sends 10 to client2
    assert_eq!(true, client2.with()); // enters nesting
    assert_eq!(true, client2.with()); // receives 10 from client1, sends back 20, pops out of nesting
    assert_eq!(true, client1.with()); // receives 20 from client2, pops out of nesting
    assert_eq!(true, client1.with()); // sends 10 to client2
    assert_eq!(true, client2.with()); // receives 10 from client1
}

#[test]
fn initialize_protocol() {
    use nemo::channels::Blocking;

    struct MyProtocol;

    type SendNumber = Send<usize, GetNumber>;
    type GetNumber = Recv<usize, End>;

    type GetNumberFirst = Recv<usize, SendNumberSecond>;
    type SendNumberSecond = Send<usize, End>;

    impl Protocol for MyProtocol {
        type Initial = SendNumber;
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, GetNumber> for MyProtocol {
        fn with(this: Channel<Self, I, E, GetNumber>) -> Defer<Self, I> {
            match this.recv() {
                Ok((msg, session)) => {
                    assert_eq!(msg, 20);
                    session.defer()
                },
                Err(_) => {
                    panic!("should have received something")
                }
            }
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, GetNumberFirst> for MyProtocol {
        fn with(this: Channel<Self, I, E, GetNumberFirst>) -> Defer<Self, I> {
            match this.recv() {
                Ok((msg, session)) => {
                    assert_eq!(msg, 10);
                    session.send(20).defer()
                },
                Err(_) => {
                    panic!("should have received something")
                }
            }
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, SendNumber> for MyProtocol {
        fn with(this: Channel<Self, I, E, SendNumber>) -> Defer<Self, I> {
            this.send(10).defer()
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, End> for MyProtocol {
        fn with(this: Channel<Self, I, E, End>) -> Defer<Self, I> {
            this.close()
        }
    }

    let (client1, client2) = Blocking::new::<MyProtocol>(MyProtocol, MyProtocol);

    let mut client1 = client1.defer();
    let mut client2 = client2.defer();

    assert_eq!(true, client1.with()); // sends 10 to client2
    assert_eq!(true, client2.with()); // receives 10, sends 10 to client1
    assert_eq!(true, client1.with()); // receives 10 from client2
    assert_eq!(false, client2.with()); // End
    assert_eq!(false, client1.with()); // End
}<commit_msg>Add additional test for a non-finally Choose, just in case.<commit_after>#![feature(type_macros)]

#[macro_use]
extern crate nemo;
use nemo::*;
use nemo::session_types::*;
use nemo::peano::*;

#[test]
fn test_proto_macro() {
    use std::marker::PhantomData;

    type MyAlias = Recv<usize, End>;

    fn get<T>() -> PhantomData<T> { PhantomData }

    macro_rules! same {
        ($t1:ty = $t2:ty) => (
            {
                let _: PhantomData<$t1> = get::<$t2>();
            }
        )
    }

    // Send/Recv
    same!(Recv<usize, End> = proto!(Recv usize, End));
    same!(Send<usize, End> = proto!(Send usize, End));
    same!(Send<usize, Recv<u8, End>> = proto!(Send usize, Recv u8, End));
    same!(Recv<usize, Send<u8, End>> = proto!(Recv usize, Send u8, End));

    // Nest/Escape
    same!(Nest<Send<usize, Escape<Z>>> = proto!(
        loop {
            Send usize,
            continue 0
        }
    ));

    same!(Nest<Recv<usize, Nest<Send<usize, Escape<S<Z>>>>>> = proto!(
        loop {
            Recv usize,
            loop {
                Send usize,
                continue 1
            }
        }
    ));

    // Choose/Accept

    same!(Choose<Recv<usize, End>, Finally<End>> = proto!(
        Choose {
            {
                Recv usize,
                End
            },
            End
        }
    ));

    same!(
        Nest<
            Recv<usize,
                 Choose<
                    Recv<usize, Send<usize, Escape<Z>>>,
                    Choose<
                        Send<usize, End>,
                        Finally<
                            Nest<
                                Recv<usize,
                                     Choose<
                                        Escape<Z>,
                                        Finally<Escape<S<Z>>>
                                     >
                                >
                            >
                        >
                    >
                 >
            >
        >
     = proto!(
        loop {
            Recv usize,
            Choose {
                {
                    Recv usize,
                    Send usize,
                    continue 0
                },
                {
                    Send usize,
                    End
                },
                {
                    loop {
                        Recv usize,
                        Choose {
                            {continue 0},
                            {continue 1}
                        }
                    }
                }
            }
        }
    ));

    same!(
        Nest<
            Recv<usize,
                 Accept<
                    Recv<usize, Send<usize, Escape<Z>>>,
                    Accept<
                        Send<usize, End>,
                        Finally<
                            Nest<
                                Recv<usize,
                                     Accept<
                                        Escape<Z>,
                                        Finally<Escape<S<Z>>>
                                     >
                                >
                            >
                        >
                    >
                 >
            >
        >
     = proto!(
        loop {
            Recv usize,
            Accept {
                {
                    Recv usize,
                    Send usize,
                    continue 0
                },
                {
                    Send usize,
                    End
                },
                {
                    loop {
                        Recv usize,
                        Accept {
                            {continue 0},
                            {continue 1}
                        }
                    }
                }
            }
        }
    ));

    same!(Recv<usize, End> = proto!(goto MyAlias));
}

#[test]
fn choosing_protocol() {
    use nemo::channels::Blocking;

    struct MyProtocol;

    type SendString = Send<String, End>;
    type SendUsize = Send<usize, End>;
    type SendIsize = Send<isize, End>;
    type Orig = Choose<SendString, Choose<SendUsize, Finally<SendIsize>>>;

    type DualSendString = Recv<String, End>;
    type DualSendUsize = Recv<usize, End>;
    type DualSendIsize = Recv<isize, End>;
    type DualOrig = Accept<DualSendString, Accept<DualSendUsize, Finally<DualSendIsize>>>;

    impl Protocol for MyProtocol {
        type Initial = Orig;
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, Orig> for MyProtocol {
        fn with(this: Channel<Self, I, E, Orig>) -> Defer<Self, I> {
            this.choose::<SendIsize>().send(10).close()
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualOrig> for MyProtocol {
        fn with(this: Channel<Self, I, E, DualOrig>) -> Defer<Self, I> {
            this.accept().ok().unwrap()
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualSendString> for MyProtocol {
        fn with(_: Channel<Self, I, E, DualSendString>) -> Defer<Self, I> {
            panic!("should not have received a string..")
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualSendUsize> for MyProtocol {
        fn with(_: Channel<Self, I, E, DualSendUsize>) -> Defer<Self, I> {
            panic!("should not have received a usize..")
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualSendIsize> for MyProtocol {
        fn with(this: Channel<Self, I, E, DualSendIsize>) -> Defer<Self, I> {
            match this.recv() {
                Ok((msg, sess)) => {
                    assert_eq!(msg, 10);

                    sess.close()
                },
                Err(_) => {
                    panic!("expected to get a message...");
                }
            }
        }
    }

    let (client1, client2) = Blocking::new::<MyProtocol>(MyProtocol, MyProtocol);

    let mut client1 = client1.defer();
    let mut client2 = client2.defer();

    assert_eq!(false, client1.with()); // client1 chooses a protocol, sends 10, closes channel
    assert_eq!(false, client2.with()); // client2 accepts the protocol, handles it immediately, closes
}

#[test]
fn choosing_protocol_2() {
    use nemo::channels::Blocking;

    struct MyProtocol;

    type SendString = Send<String, End>;
    type SendUsize = Send<usize, End>;
    type SendIsize = Send<isize, End>;
    type Orig = Choose<SendString, Choose<SendUsize, Finally<SendIsize>>>;

    type DualSendString = Recv<String, End>;
    type DualSendUsize = Recv<usize, End>;
    type DualSendIsize = Recv<isize, End>;
    type DualOrig = Accept<DualSendString, Accept<DualSendUsize, Finally<DualSendIsize>>>;

    impl Protocol for MyProtocol {
        type Initial = Orig;
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, Orig> for MyProtocol {
        fn with(this: Channel<Self, I, E, Orig>) -> Defer<Self, I> {
            this.choose::<SendUsize>().send(10).close()
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualOrig> for MyProtocol {
        fn with(this: Channel<Self, I, E, DualOrig>) -> Defer<Self, I> {
            this.accept().ok().unwrap()
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualSendString> for MyProtocol {
        fn with(_: Channel<Self, I, E, DualSendString>) -> Defer<Self, I> {
            panic!("should not have received a string..")
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualSendUsize> for MyProtocol {
        fn with(this: Channel<Self, I, E, DualSendUsize>) -> Defer<Self, I> {
            match this.recv() {
                Ok((msg, sess)) => {
                    assert_eq!(msg, 10);

                    sess.close()
                },
                Err(_) => {
                    panic!("expected to get a message...");
                }
            }
        }
    }

    impl<I: Transfers<String> + Transfers<usize> + Transfers<isize>, E: SessionType> Handler<I, E, DualSendIsize> for MyProtocol {
        fn with(_: Channel<Self, I, E, DualSendIsize>) -> Defer<Self, I> {
            panic!("should not have received an isize..")
        }
    }

    let (client1, client2) = Blocking::new::<MyProtocol>(MyProtocol, MyProtocol);

    let mut client1 = client1.defer();
    let mut client2 = client2.defer();

    assert_eq!(false, client1.with()); // client1 chooses a protocol, sends 10, closes channel
    assert_eq!(false, client2.with()); // client2 accepts the protocol, handles it immediately, closes
}

#[test]
fn recursive_protocol() {
    use nemo::channels::Blocking;

    struct MyProtocol;

    type Orig = Nest<OrigEntered>;
    type OrigEntered = Send<usize, AwaitingNumber>;
    type AwaitingNumber = Recv<usize, Escape<Z>>;

    type DualOrig = Nest<DualOrigEntered>;
    type DualOrigEntered = Recv<usize, Send<usize, Escape<Z>>>;

    impl Protocol for MyProtocol {
        type Initial = Orig;
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, Orig> for MyProtocol {
        fn with(this: Channel<Self, I, E, Orig>) -> Defer<Self, I> {
            this.enter().defer()
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, (OrigEntered, E), OrigEntered> for MyProtocol {
        fn with(this: Channel<Self, I, (OrigEntered, E), OrigEntered>) -> Defer<Self, I> {
            this.send(10).defer()
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, (OrigEntered, E), AwaitingNumber> for MyProtocol {
        fn with(this: Channel<Self, I, (OrigEntered, E), AwaitingNumber>) -> Defer<Self, I> {
            match this.recv() {
                Ok((msg, this)) => {
                    assert_eq!(msg, 20);
                    this.pop().defer()
                },
                Err(_) => panic!("should have received a message")
            }
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, DualOrig> for MyProtocol {
        fn with(this: Channel<Self, I, E, DualOrig>) -> Defer<Self, I> {
            this.enter().defer()
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, (DualOrigEntered, E), DualOrigEntered> for MyProtocol {
        fn with(this: Channel<Self, I, (DualOrigEntered, E), DualOrigEntered>) -> Defer<Self, I> {
            match this.recv() {
                Ok((msg, this)) => {
                    assert_eq!(msg, 10);
                    this.send(20).pop().defer()
                },
                Err(_) => panic!("should have received a message")
            }
        }
    }

    let (client1, client2) = Blocking::new::<MyProtocol>(MyProtocol, MyProtocol);

    let mut client1 = client1.defer();
    let mut client2 = client2.defer();

    assert_eq!(true, client1.with()); // enters nesting
    assert_eq!(true, client1.with()); // sends 10 to client2
    assert_eq!(true, client2.with()); // enters nesting
    assert_eq!(true, client2.with()); // receives 10 from client1, sends back 20, pops out of nesting
    assert_eq!(true, client1.with()); // receives 20 from client2, pops out of nesting
    assert_eq!(true, client1.with()); // sends 10 to client2
    assert_eq!(true, client2.with()); // receives 10 from client1
}

#[test]
fn initialize_protocol() {
    use nemo::channels::Blocking;

    struct MyProtocol;

    type SendNumber = Send<usize, GetNumber>;
    type GetNumber = Recv<usize, End>;

    type GetNumberFirst = Recv<usize, SendNumberSecond>;
    type SendNumberSecond = Send<usize, End>;

    impl Protocol for MyProtocol {
        type Initial = SendNumber;
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, GetNumber> for MyProtocol {
        fn with(this: Channel<Self, I, E, GetNumber>) -> Defer<Self, I> {
            match this.recv() {
                Ok((msg, session)) => {
                    assert_eq!(msg, 20);
                    session.defer()
                },
                Err(_) => {
                    panic!("should have received something")
                }
            }
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, GetNumberFirst> for MyProtocol {
        fn with(this: Channel<Self, I, E, GetNumberFirst>) -> Defer<Self, I> {
            match this.recv() {
                Ok((msg, session)) => {
                    assert_eq!(msg, 10);
                    session.send(20).defer()
                },
                Err(_) => {
                    panic!("should have received something")
                }
            }
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, SendNumber> for MyProtocol {
        fn with(this: Channel<Self, I, E, SendNumber>) -> Defer<Self, I> {
            this.send(10).defer()
        }
    }

    impl<I: Transfers<usize>, E: SessionType> Handler<I, E, End> for MyProtocol {
        fn with(this: Channel<Self, I, E, End>) -> Defer<Self, I> {
            this.close()
        }
    }

    let (client1, client2) = Blocking::new::<MyProtocol>(MyProtocol, MyProtocol);

    let mut client1 = client1.defer();
    let mut client2 = client2.defer();

    assert_eq!(true, client1.with()); // sends 10 to client2
    assert_eq!(true, client2.with()); // receives 10, sends 10 to client1
    assert_eq!(true, client1.with()); // receives 10 from client2
    assert_eq!(false, client2.with()); // End
    assert_eq!(false, client1.with()); // End
}<|endoftext|>


<commit_before>use std::any::TypeId;
use std::backtrace::{Backtrace, BacktraceStatus};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

/// The `Error` type, a wrapper around a dynamic error type.
///
/// `Error` functions a lot like `Box<dyn std::error::Error>`, with these
/// differences:
///
/// - `Error` requires that the error is `Send`, `Sync`, and `'static`
/// - `Error` guarantees that a backtrace will exist, even if the error type
///   did not provide one
/// - `Error` is represented as a narrow pointer - exactly one word in size,
///   instead of two.
pub struct Error {
    inner: Box<ErrorImpl<()>>,
}

impl Error {
    /// Create a new error object from any error type.
    ///
    /// The error type must be threadsafe and `'static`, so that the `Error`
    /// will be as well.
    ///
    /// If the error type does not provide a backtrace, a backtrace will be
    /// created here to ensure that a backtrace exists.
    pub fn new<E>(error: E) -> Error
    where
        E: StdError + Send + Sync + 'static,
    {
        Error::construct(error, TypeId::of::<E>())
    }

    #[doc(hidden)]
    pub fn new_adhoc<M>(message: M) -> Error
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        Error::construct(MessageError(message), TypeId::of::<M>())
    }

    fn construct<E>(error: E, type_id: TypeId) -> Error
    where
        E: StdError + Send + Sync + 'static,
    {
        unsafe {
            let backtrace = match error.backtrace() {
                Some(_) => None,
                None => Some(Backtrace::capture()),
            };
            let obj: TraitObject = mem::transmute(&error as &dyn StdError);
            let vtable = obj.vtable;
            let inner = ErrorImpl {
                vtable,
                type_id,
                backtrace,
                error,
            };
            Error {
                inner: mem::transmute(Box::new(inner)),
            }
        }
    }

    /// View this error object as the underlying error.
    pub fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        &**self
    }

    /// View this error object as the underlying error, mutably.
    pub fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        &mut **self
    }

    /// Get the backtrace for this Error.
    pub fn backtrace(&self) -> &Backtrace {
        // NB: this unwrap can only fail if the underlying error's backtrace
        // method is nondeterministic, which would only happen in maliciously
        // constructed code
        self.inner
            .backtrace
            .as_ref()
            .or_else(|| self.inner.error().backtrace())
            .expect("backtrace capture failed")
    }

    /// An iterator of errors contained by this Error.
    ///
    /// This iterator will visit every error in the "cause chain" of this error
    /// object, beginning with the error that this error object was created
    /// from.
    pub fn errors(&self) -> Errors<'_> {
        Errors {
            next: Some(self.inner.error()),
        }
    }

    /// Returns `true` if `E` is the type wrapped by this error object.
    pub fn is<E>(&self) -> bool
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        TypeId::of::<E>() == self.inner.type_id
    }

    /// Attempt to downcast the error object to a concrete type.
    pub fn downcast<E>(self) -> Result<E, Error>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if let Some(error) = self.downcast_ref::<E>() {
            unsafe {
                let error = ptr::read(error);
                drop(ptr::read(&self.inner));
                mem::forget(self);
                Ok(error)
            }
        } else {
            Err(self)
        }
    }

    /// Downcast this error object by reference.
    pub fn downcast_ref<E>(&self) -> Option<&E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&*(self.inner.error() as *const dyn StdError as *const E)) }
        } else {
            None
        }
    }

    /// Downcast this error object by mutable reference.
    pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&mut *(self.inner.error_mut() as *mut dyn StdError as *mut E)) }
        } else {
            None
        }
    }
}

impl<E> From<E> for Error
where
    E: StdError + Send + Sync + 'static,
{
    fn from(error: E) -> Error {
        Error::new(error)
    }
}

impl Deref for Error {
    type Target = dyn StdError + Send + Sync + 'static;
    fn deref(&self) -> &Self::Target {
        self.inner.error()
    }
}

impl DerefMut for Error {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.inner.error_mut()
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}", self.inner.error())?;

        let mut errors = self.errors().skip(1).enumerate();

        if let Some((n, error)) = errors.next() {
            writeln!(f, "\ncaused by:")?;
            writeln!(f, "\t{}: {}", n, error)?;
            for (n, error) in errors {
                writeln!(f, "\t{}: {}", n, error)?;
            }
        }

        let backtrace = self.backtrace();

        match backtrace.status() {
            BacktraceStatus::Captured => {
                writeln!(f, "\n{}", backtrace)?;
            }
            BacktraceStatus::Disabled => {
                writeln!(
                    f,
                    "\nbacktrace disabled; run with RUST_BACKTRACE=1 environment variable to display a backtrace"
                )?;
            }
            _ => {}
        }

        Ok(())
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.inner.error())
    }
}

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

impl Drop for Error {
    fn drop(&mut self) {
        unsafe { ptr::drop_in_place(self.inner.error_mut()) }
    }
}

// repr C to ensure that `E` remains in the final position
#[repr(C)]
struct ErrorImpl<E> {
    vtable: *const (),
    type_id: TypeId,
    backtrace: Option<Backtrace>,
    error: E,
}

// repr C to ensure that transmuting from trait objects is safe
#[repr(C)]
struct TraitObject {
    data: *const (),
    vtable: *const (),
}

#[repr(transparent)]
struct MessageError<M>(M)
where
    M: Display + Debug;

impl<M> Debug for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl<M> Display for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}

impl ErrorImpl<()> {
    fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        unsafe {
            mem::transmute(TraitObject {
                data: &self.error,
                vtable: self.vtable,
            })
        }
    }

    fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        unsafe {
            mem::transmute(TraitObject {
                data: &mut self.error,
                vtable: self.vtable,
            })
        }
    }
}

/// Iterator of errors in an `Error`.
pub struct Errors<'a> {
    next: Option<&'a (dyn StdError + 'static)>,
}

impl<'a> Iterator for Errors<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.next.take()?;
        self.next = next.source();
        Some(next)
    }
}

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

    use std::marker::Unpin;
    use std::mem;

    #[test]
    fn size_of_error() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[allow(dead_code)]
    fn assert_error_autotraits()
    where
        Error: Unpin + Send + Sync + 'static,
    {
    }

    #[test]
    fn destructors_work() {
        use std::sync::*;

        #[derive(Debug)]
        struct HasDrop(Box<Arc<Mutex<bool>>>);
        impl StdError for HasDrop {}
        impl Display for HasDrop {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "does something")
            }
        }
        impl Drop for HasDrop {
            fn drop(&mut self) {
                let mut has_dropped = self.0.lock().unwrap();
                assert!(!*has_dropped);
                *has_dropped = true;
            }
        }

        let has_dropped = Arc::new(Mutex::new(false));

        drop(Error::from(HasDrop(Box::new(has_dropped.clone()))));

        assert!(*has_dropped.lock().unwrap());
    }
}
<commit_msg>Remove trait bounds from MessageError struct<commit_after>use std::any::TypeId;
use std::backtrace::{Backtrace, BacktraceStatus};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;

/// The `Error` type, a wrapper around a dynamic error type.
///
/// `Error` functions a lot like `Box<dyn std::error::Error>`, with these
/// differences:
///
/// - `Error` requires that the error is `Send`, `Sync`, and `'static`
/// - `Error` guarantees that a backtrace will exist, even if the error type
///   did not provide one
/// - `Error` is represented as a narrow pointer - exactly one word in size,
///   instead of two.
pub struct Error {
    inner: Box<ErrorImpl<()>>,
}

impl Error {
    /// Create a new error object from any error type.
    ///
    /// The error type must be threadsafe and `'static`, so that the `Error`
    /// will be as well.
    ///
    /// If the error type does not provide a backtrace, a backtrace will be
    /// created here to ensure that a backtrace exists.
    pub fn new<E>(error: E) -> Error
    where
        E: StdError + Send + Sync + 'static,
    {
        Error::construct(error, TypeId::of::<E>())
    }

    #[doc(hidden)]
    pub fn new_adhoc<M>(message: M) -> Error
    where
        M: Display + Debug + Send + Sync + 'static,
    {
        Error::construct(MessageError(message), TypeId::of::<M>())
    }

    fn construct<E>(error: E, type_id: TypeId) -> Error
    where
        E: StdError + Send + Sync + 'static,
    {
        unsafe {
            let backtrace = match error.backtrace() {
                Some(_) => None,
                None => Some(Backtrace::capture()),
            };
            let obj: TraitObject = mem::transmute(&error as &dyn StdError);
            let vtable = obj.vtable;
            let inner = ErrorImpl {
                vtable,
                type_id,
                backtrace,
                error,
            };
            Error {
                inner: mem::transmute(Box::new(inner)),
            }
        }
    }

    /// View this error object as the underlying error.
    pub fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        &**self
    }

    /// View this error object as the underlying error, mutably.
    pub fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        &mut **self
    }

    /// Get the backtrace for this Error.
    pub fn backtrace(&self) -> &Backtrace {
        // NB: this unwrap can only fail if the underlying error's backtrace
        // method is nondeterministic, which would only happen in maliciously
        // constructed code
        self.inner
            .backtrace
            .as_ref()
            .or_else(|| self.inner.error().backtrace())
            .expect("backtrace capture failed")
    }

    /// An iterator of errors contained by this Error.
    ///
    /// This iterator will visit every error in the "cause chain" of this error
    /// object, beginning with the error that this error object was created
    /// from.
    pub fn errors(&self) -> Errors<'_> {
        Errors {
            next: Some(self.inner.error()),
        }
    }

    /// Returns `true` if `E` is the type wrapped by this error object.
    pub fn is<E>(&self) -> bool
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        TypeId::of::<E>() == self.inner.type_id
    }

    /// Attempt to downcast the error object to a concrete type.
    pub fn downcast<E>(self) -> Result<E, Error>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if let Some(error) = self.downcast_ref::<E>() {
            unsafe {
                let error = ptr::read(error);
                drop(ptr::read(&self.inner));
                mem::forget(self);
                Ok(error)
            }
        } else {
            Err(self)
        }
    }

    /// Downcast this error object by reference.
    pub fn downcast_ref<E>(&self) -> Option<&E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&*(self.inner.error() as *const dyn StdError as *const E)) }
        } else {
            None
        }
    }

    /// Downcast this error object by mutable reference.
    pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
    where
        E: Display + Debug + Send + Sync + 'static,
    {
        if self.is::<E>() {
            unsafe { Some(&mut *(self.inner.error_mut() as *mut dyn StdError as *mut E)) }
        } else {
            None
        }
    }
}

impl<E> From<E> for Error
where
    E: StdError + Send + Sync + 'static,
{
    fn from(error: E) -> Error {
        Error::new(error)
    }
}

impl Deref for Error {
    type Target = dyn StdError + Send + Sync + 'static;
    fn deref(&self) -> &Self::Target {
        self.inner.error()
    }
}

impl DerefMut for Error {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.inner.error_mut()
    }
}

impl Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "{}", self.inner.error())?;

        let mut errors = self.errors().skip(1).enumerate();

        if let Some((n, error)) = errors.next() {
            writeln!(f, "\ncaused by:")?;
            writeln!(f, "\t{}: {}", n, error)?;
            for (n, error) in errors {
                writeln!(f, "\t{}: {}", n, error)?;
            }
        }

        let backtrace = self.backtrace();

        match backtrace.status() {
            BacktraceStatus::Captured => {
                writeln!(f, "\n{}", backtrace)?;
            }
            BacktraceStatus::Disabled => {
                writeln!(
                    f,
                    "\nbacktrace disabled; run with RUST_BACKTRACE=1 environment variable to display a backtrace"
                )?;
            }
            _ => {}
        }

        Ok(())
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.inner.error())
    }
}

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

impl Drop for Error {
    fn drop(&mut self) {
        unsafe { ptr::drop_in_place(self.inner.error_mut()) }
    }
}

// repr C to ensure that `E` remains in the final position
#[repr(C)]
struct ErrorImpl<E> {
    vtable: *const (),
    type_id: TypeId,
    backtrace: Option<Backtrace>,
    error: E,
}

// repr C to ensure that transmuting from trait objects is safe
#[repr(C)]
struct TraitObject {
    data: *const (),
    vtable: *const (),
}

#[repr(transparent)]
struct MessageError<M>(M);

impl<M> Debug for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(&self.0, f)
    }
}

impl<M> Display for MessageError<M>
where
    M: Display + Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.0, f)
    }
}

impl<M> StdError for MessageError<M> where M: Display + Debug + 'static {}

impl ErrorImpl<()> {
    fn error(&self) -> &(dyn StdError + Send + Sync + 'static) {
        unsafe {
            mem::transmute(TraitObject {
                data: &self.error,
                vtable: self.vtable,
            })
        }
    }

    fn error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {
        unsafe {
            mem::transmute(TraitObject {
                data: &mut self.error,
                vtable: self.vtable,
            })
        }
    }
}

/// Iterator of errors in an `Error`.
pub struct Errors<'a> {
    next: Option<&'a (dyn StdError + 'static)>,
}

impl<'a> Iterator for Errors<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.next.take()?;
        self.next = next.source();
        Some(next)
    }
}

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

    use std::marker::Unpin;
    use std::mem;

    #[test]
    fn size_of_error() {
        assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
    }

    #[allow(dead_code)]
    fn assert_error_autotraits()
    where
        Error: Unpin + Send + Sync + 'static,
    {
    }

    #[test]
    fn destructors_work() {
        use std::sync::*;

        #[derive(Debug)]
        struct HasDrop(Box<Arc<Mutex<bool>>>);
        impl StdError for HasDrop {}
        impl Display for HasDrop {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "does something")
            }
        }
        impl Drop for HasDrop {
            fn drop(&mut self) {
                let mut has_dropped = self.0.lock().unwrap();
                assert!(!*has_dropped);
                *has_dropped = true;
            }
        }

        let has_dropped = Arc::new(Mutex::new(false));

        drop(Error::from(HasDrop(Box::new(has_dropped.clone()))));

        assert!(*has_dropped.lock().unwrap());
    }
}
<|endoftext|>


<commit_before>use std;
use hyper;

#[derive(Debug)]
pub enum Error {
    InvalidResponse,
    MissingValue(&'static str),
    NetError(hyper::error::Error),
    IOError(std::io::Error),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            Error::InvalidResponse => write!(f, "Invalid response received"),
            Error::MissingValue(ref val) => write!(f, "Value missing from response: {}", val),
            Error::NetError(ref err) => write!(f, "Network error: {}", err),
            Error::IOError(ref err) => write!(f, "IO Error: {}", err),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidResponse => "Invalid response received",
            Error::MissingValue(_) => "Value missing from response",
            Error::NetError(ref err) => err.description(),
            Error::IOError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            Error::NetError(ref err) => Some(err),
            Error::IOError(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<hyper::error::Error> for Error {
    fn from(err: hyper::error::Error) -> Error {
        Error::NetError(err)
    }
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error {
        Error::IOError(err)
    }
}
<commit_msg>add documentation comments<commit_after>use std;
use hyper;

///A set of errors that can occur when interacting with Twitter.
#[derive(Debug)]
pub enum Error {
    ///The response from Twitter was formatted incorrectly or in
    ///an unexpected manner.
    InvalidResponse,
    ///The response from Twitter was missing an expected value.
    ///The enclosed value was the expected parameter.
    MissingValue(&'static str),
    ///The web request experienced an error. The enclosed value
    ///was returned from hyper.
    NetError(hyper::error::Error),
    ///An error was experienced while processing the response
    ///stream. The enclosed value was returned from libstd.
    IOError(std::io::Error),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            Error::InvalidResponse => write!(f, "Invalid response received"),
            Error::MissingValue(ref val) => write!(f, "Value missing from response: {}", val),
            Error::NetError(ref err) => write!(f, "Network error: {}", err),
            Error::IOError(ref err) => write!(f, "IO Error: {}", err),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidResponse => "Invalid response received",
            Error::MissingValue(_) => "Value missing from response",
            Error::NetError(ref err) => err.description(),
            Error::IOError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            Error::NetError(ref err) => Some(err),
            Error::IOError(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<hyper::error::Error> for Error {
    fn from(err: hyper::error::Error) -> Error {
        Error::NetError(err)
    }
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error {
        Error::IOError(err)
    }
}
<|endoftext|>


<commit_before>//! Error types and converters.

use data_encoding::DecodeError;
use std::io;
use std::path::Path;
use thiserror::Error;

use crate::metadata::Role;

/// Error type for all TUF related errors.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum Error {
    /// The metadata had a bad signature.
    #[error("bad signature")]
    BadSignature,

    /// There was a problem encoding or decoding.
    #[error("encoding: {0}")]
    Encoding(String),

    /// Metadata was expired.
    #[error("expired {0} metadata")]
    ExpiredMetadata(Role),

    /// An illegal argument was passed into a function.
    #[error("illegal argument: {0}")]
    IllegalArgument(String),

    /// The metadata was missing, so an operation could not be completed.
    #[error("missing {0} metadata")]
    MissingMetadata(Role),

    /// There were no available hash algorithms.
    #[error("no supported hash algorithm")]
    NoSupportedHashAlgorithm,

    /// The metadata or target was not found.
    #[error("not found")]
    NotFound,

    /// Opaque error type, to be interpreted similar to HTTP 500. Something went wrong, and you may
    /// or may not be able to do anything about it.
    #[error("opaque: {0}")]
    Opaque(String),

    /// There was a library internal error. These errors are *ALWAYS* bugs and should be reported.
    #[error("programming: {0}")]
    Programming(String),

    /// The target is unavailable. This may mean it is either not in the metadata or the metadata
    /// chain to the target cannot be fully verified.
    #[error("target unavailable")]
    TargetUnavailable,

    /// There is no known or available hash algorithm.
    #[error("unknown hash algorithm: {0}")]
    UnkonwnHashAlgorithm(String),

    /// There is no known or available key type.
    #[error("unknown key type: {0}")]
    UnknownKeyType(String),

    /// The metadata or target failed to verify.
    #[error("verification failure: {0}")]
    VerificationFailure(String),
}

impl From<serde_json::error::Error> for Error {
    fn from(err: serde_json::error::Error) -> Error {
        Error::Encoding(format!("JSON: {:?}", err))
    }
}

impl Error {
    /// Helper to include the path that causd the error for FS I/O errors.
    pub fn from_io(err: &io::Error, path: &Path) -> Error {
        Error::Opaque(format!("Path {:?} : {:?}", path, err))
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        match err.kind() {
            std::io::ErrorKind::NotFound => Error::NotFound,
            _ => Error::Opaque(format!("IO: {:?}", err)),
        }
    }
}

impl From<http::Error> for Error {
    fn from(err: http::Error) -> Error {
        Error::Opaque(format!("Http: {:?}", err))
    }
}

impl From<hyper::Error> for Error {
    fn from(err: hyper::Error) -> Error {
        Error::Opaque(format!("Hyper: {:?}", err))
    }
}

impl From<DecodeError> for Error {
    fn from(err: DecodeError) -> Error {
        Error::Encoding(format!("{:?}", err))
    }
}

impl From<derp::Error> for Error {
    fn from(err: derp::Error) -> Error {
        Error::Encoding(format!("DER: {:?}", err))
    }
}

impl From<tempfile::PersistError> for Error {
    fn from(err: tempfile::PersistError) -> Error {
        Error::Opaque(format!("Error persisting temp file: {:?}", err))
    }
}

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

    #[test]
    fn verify_io_error_display_string() {
        let err = Error::from(io::Error::from(std::io::ErrorKind::NotFound));
        assert_eq!(err.to_string(), "not found");
        assert_eq!(Error::NotFound.to_string(), "not found");

        let err = Error::from(io::Error::from(std::io::ErrorKind::PermissionDenied));
        assert_eq!(err.to_string(), "opaque: IO: Kind(PermissionDenied)");
    }
}
<commit_msg>Adding Hyper and Http error variants. Also, fixes a typo for UnknownHashAlgorithm<commit_after>//! Error types and converters.

use data_encoding::DecodeError;
use std::io;
use std::path::Path;
use thiserror::Error;

use crate::metadata::Role;

/// Error type for all TUF related errors.
#[derive(Error, Debug, PartialEq, Eq)]
pub enum Error {
    /// The metadata had a bad signature.
    #[error("bad signature")]
    BadSignature,

    /// There was a problem encoding or decoding.
    #[error("encoding: {0}")]
    Encoding(String),

    /// Metadata was expired.
    #[error("expired {0} metadata")]
    ExpiredMetadata(Role),

    /// An illegal argument was passed into a function.
    #[error("illegal argument: {0}")]
    IllegalArgument(String),

    /// Generic error for HTTP connections.
    #[error("http: {0}")]
    Http(String),

    /// Errors that can occur parsing HTTP streams.
    #[error("hyper: {0}")]
    Hyper(String),

    /// The metadata was missing, so an operation could not be completed.
    #[error("missing {0} metadata")]
    MissingMetadata(Role),

    /// There were no available hash algorithms.
    #[error("no supported hash algorithm")]
    NoSupportedHashAlgorithm,

    /// The metadata or target was not found.
    #[error("not found")]
    NotFound,

    /// Opaque error type, to be interpreted similar to HTTP 500. Something went wrong, and you may
    /// or may not be able to do anything about it.
    #[error("opaque: {0}")]
    Opaque(String),

    /// There was a library internal error. These errors are *ALWAYS* bugs and should be reported.
    #[error("programming: {0}")]
    Programming(String),

    /// The target is unavailable. This may mean it is either not in the metadata or the metadata
    /// chain to the target cannot be fully verified.
    #[error("target unavailable")]
    TargetUnavailable,

    /// There is no known or available hash algorithm.
    #[error("unknown hash algorithm: {0}")]
    UnknownHashAlgorithm(String),

    /// There is no known or available key type.
    #[error("unknown key type: {0}")]
    UnknownKeyType(String),

    /// The metadata or target failed to verify.
    #[error("verification failure: {0}")]
    VerificationFailure(String),
}

impl From<serde_json::error::Error> for Error {
    fn from(err: serde_json::error::Error) -> Error {
        Error::Encoding(format!("JSON: {:?}", err))
    }
}

impl Error {
    /// Helper to include the path that causd the error for FS I/O errors.
    pub fn from_io(err: &io::Error, path: &Path) -> Error {
        Error::Opaque(format!("Path {:?} : {:?}", path, err))
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        match err.kind() {
            std::io::ErrorKind::NotFound => Error::NotFound,
            _ => Error::Opaque(format!("IO: {:?}", err)),
        }
    }
}

impl From<http::Error> for Error {
    fn from(err: http::Error) -> Error {
        Error::Http(format!("Http: {:?}", err))
    }
}

impl From<hyper::Error> for Error {
    fn from(err: hyper::Error) -> Error {
        Error::Hyper(format!("Hyper: {:?}", err))
    }
}

impl From<DecodeError> for Error {
    fn from(err: DecodeError) -> Error {
        Error::Encoding(format!("{:?}", err))
    }
}

impl From<derp::Error> for Error {
    fn from(err: derp::Error) -> Error {
        Error::Encoding(format!("DER: {:?}", err))
    }
}

impl From<tempfile::PersistError> for Error {
    fn from(err: tempfile::PersistError) -> Error {
        Error::Opaque(format!("Error persisting temp file: {:?}", err))
    }
}

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

    #[test]
    fn verify_io_error_display_string() {
        let err = Error::from(io::Error::from(std::io::ErrorKind::NotFound));
        assert_eq!(err.to_string(), "not found");
        assert_eq!(Error::NotFound.to_string(), "not found");

        let err = Error::from(io::Error::from(std::io::ErrorKind::PermissionDenied));
        assert_eq!(err.to_string(), "opaque: IO: Kind(PermissionDenied)");
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use ansi_term::Colour;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ErrorKind {
    UndefinedVar = 0,
    TooFewArguments = 1,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ErrorLevel {
    Info,
    Warning,
    Error,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Error(pub ErrorLevel, pub ErrorKind, pub &'static str);

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let colour_level = match self.0 {
            ErrorLevel::Info => Colour::Yellow.paint("Info"),

            // ansi_term does not have orange for some reason
            ErrorLevel::Warning => Colour::RGB(255, 210, 0).paint("Warning"),
            ErrorLevel::Error => Colour::Red.paint("Error"),
        };

        // TODO: Remove clone
        write!(f, "[{}] (E{}) {}", colour_level, self.1 as i32, self.2)
    }
}

#[derive(Debug)]
pub struct ErrorStack(pub Vec<Error>);

impl fmt::Display for ErrorStack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for error in &self.0 {
            // TODO: Remove this unwrap
            write!(f, "{}", error).unwrap();
        }

        write!(f, "")
    }
}
<commit_msg>Add parser error Error Code<commit_after>use std::fmt;
use ansi_term::Colour;

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ErrorKind {
    UndefinedVar = 0,
    TooFewArguments = 1,
    ParseError = 2,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ErrorLevel {
    Info,
    Warning,
    Error,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Error(pub ErrorLevel, pub ErrorKind, pub &'static str);

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let colour_level = match self.0 {
            ErrorLevel::Info => Colour::Yellow.paint("Info"),

            // ansi_term does not have orange for some reason
            ErrorLevel::Warning => Colour::RGB(255, 210, 0).paint("Warning"),
            ErrorLevel::Error => Colour::Red.paint("Error"),
        };

        // TODO: Remove clone
        write!(f, "[{}] (E{}) {}", colour_level, self.1 as i32, self.2)
    }
}

#[derive(Debug)]
pub struct ErrorStack(pub Vec<Error>);

impl fmt::Display for ErrorStack {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for error in &self.0 {
            // TODO: Remove this unwrap
            write!(f, "{}", error).unwrap();
        }

        write!(f, "")
    }
}
<|endoftext|>