<commit_before>//! Resource caching smart pointer

extern crate rustc_serialize;

use std::sync::Arc;
use std::ops::Deref;
use std::hash;
use std::collections::HashMap;
use std::fmt;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};

/// A type that implements a singleton resource store.
pub trait ResourceStore<K = String> {
    fn get_resource(key: &K) -> Option<Arc<Self>> where Self: Sized;

    fn insert_resource(key: K, resource: Self);
}

/// Smart pointer for an immutable cached resource.
///
/// The semantics are similar to Arc pointers.
///
/// Resource values will serialize as their key values, so they can be attached to structures that
/// require compact serialization.
#[derive(Clone)]
pub struct Resource<T, K = String> {
    handle: Arc<T>,
    key: K,
}

impl<T: Sized, K> AsRef<T> for Resource<T, K> {
    fn as_ref(&self) -> &T {
        self.handle.as_ref()
    }
}

impl<T: Sized, K> Deref for Resource<T, K> {
    type Target = T;

    #[inline(always)]
    fn deref(&self) -> &T {
        self.handle.deref()
    }
}

impl<T> Encodable for Resource<T> {
    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> { self.key.encode(e) }
}

impl<T: ResourceStore> Decodable for Resource<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let key: String = Decodable::decode(d)?;;;
        Ok(Self::new(key).unwrap())
    }
}

impl<T, K: hash::Hash> hash::Hash for Resource<T, K> {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.key.hash(state);
    }
}

impl<T, K: PartialEq> PartialEq for Resource<T, K> {
    fn eq(&self, other: &Self) -> bool {
        self.key.eq(&other.key)
    }
}

impl<T, K: Eq> Eq for Resource<T, K> {}

impl<T, K: fmt::Display> fmt::Display for Resource<T, K> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.key.fmt(formatter)
    }
}

impl<T, K: fmt::Debug> fmt::Debug for Resource<T, K> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        self.key.fmt(formatter)
    }
}

impl<K, T: ResourceStore<K>> Resource<T, K> {
    pub fn new(key: K) -> Option<Self> {
        if let Some(handle) = ResourceStore::get_resource(&key) {
            Some(Resource {
                handle: handle,
                key: key,
            })
        } else {
            None
        }
    }
}

/// A value that can be implicitly constructed given a key.
pub trait Loadable<K = String> {
    fn load(_key: &K) -> Option<Self>
        where Self: Sized
    {
        // Default implementation so that types with no load semantics can be used with
        // ResourceCache so that all inserts must be explicit.
        None
    }
}

/// A cache that associates resource values with paths.
///
/// Resources and paths are assumed to be immutable.
pub struct ResourceCache<T, K = String> {
    cache: HashMap<K, Arc<T>>,
}

impl<K: Eq + hash::Hash + Clone, T: Loadable<K>> ResourceCache<T, K> {
    pub fn new() -> ResourceCache<T, K> {
        ResourceCache { cache: HashMap::new() }
    }

    pub fn get(&mut self, key: &K) -> Option<Arc<T>> {
        if let Some(v) = self.cache.get(key) {
            return Some(v.clone());
        }

        if let Some(v) = T::load(key) {
            let v = Arc::new(v);
            self.cache.insert(key.clone(), v.clone());
            Some(v)
        } else {
            None
        }
    }

    pub fn insert(&mut self, key: K, value: T) {
        self.cache.insert(key, Arc::new(value));
    }
}

/// Implement a thread-local store for a given resource type.
///
/// Name is the identifier for the store, key and value are the types of the resource cache keys
/// and the resources.
///
///     # #[macro_use] extern crate calx_resource;
///     use calx_resource::{Resource, ResourceStore, Loadable};
///
///     // A custom resource type.
///     struct MyResource { pub text: String }
///
///     // Must be present even if there's no specific implementation.
///     impl Loadable for MyResource {}
///
///     // Generate a resource store.
///     impl_store!(MY_RESOURCE_STORE, String, MyResource);
///
///     fn main() {
///         // Save a resource in the store using a key.
///         MyResource::insert_resource(
///             "test_resource".to_string(),
///             MyResource { text: "Hello, world!".to_string() });
///
///         // Fetch a resource handle from the store using our key.
///         let handle: Resource<MyResource> =
///             Resource::new("test_resource".to_string()).unwrap();
///         assert!(&handle.text == "Hello, world!");
///     }
#[macro_export]
macro_rules! impl_store {
    ($name:ident, $key:ty, $value:ty) => {
    thread_local!(static $name: ::std::cell::RefCell<$crate::ResourceCache<$value, $key>> =
                  ::std::cell::RefCell::new($crate::ResourceCache::new()));

    impl $crate::ResourceStore<$key> for $value {
        fn get_resource(key: &$key) -> Option<::std::sync::Arc<Self>> {
            $name.with(|t| t.borrow_mut().get(key))
        }

        fn insert_resource(key: $key, value: $value) {
            $name.with(|t| t.borrow_mut().insert(key, value));
        }
    }}
}
<commit_msg>Rustfmt<commit_after>//! Resource caching smart pointer

extern crate rustc_serialize;

use std::sync::Arc;
use std::ops::Deref;
use std::hash;
use std::collections::HashMap;
use std::fmt;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};

/// A type that implements a singleton resource store.
pub trait ResourceStore<K = String> {
    fn get_resource(key: &K) -> Option<Arc<Self>> where Self: Sized;

    fn insert_resource(key: K, resource: Self);
}

/// Smart pointer for an immutable cached resource.
///
/// The semantics are similar to Arc pointers.
///
/// Resource values will serialize as their key values, so they can be attached to structures that
/// require compact serialization.
#[derive(Clone)]
pub struct Resource<T, K = String> {
    handle: Arc<T>,
    key: K,
}

impl<T: Sized, K> AsRef<T> for Resource<T, K> {
    fn as_ref(&self) -> &T { self.handle.as_ref() }
}

impl<T: Sized, K> Deref for Resource<T, K> {
    type Target = T;

    #[inline(always)]
    fn deref(&self) -> &T { self.handle.deref() }
}

impl<T> Encodable for Resource<T> {
    fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> { self.key.encode(e) }
}

impl<T: ResourceStore> Decodable for Resource<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let key: String = Decodable::decode(d)?;;;
        Ok(Self::new(key).unwrap())
    }
}

impl<T, K: hash::Hash> hash::Hash for Resource<T, K> {
    fn hash<H: hash::Hasher>(&self, state: &mut H) { self.key.hash(state); }
}

impl<T, K: PartialEq> PartialEq for Resource<T, K> {
    fn eq(&self, other: &Self) -> bool { self.key.eq(&other.key) }
}

impl<T, K: Eq> Eq for Resource<T, K> {}

impl<T, K: fmt::Display> fmt::Display for Resource<T, K> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { self.key.fmt(formatter) }
}

impl<T, K: fmt::Debug> fmt::Debug for Resource<T, K> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { self.key.fmt(formatter) }
}

impl<K, T: ResourceStore<K>> Resource<T, K> {
    pub fn new(key: K) -> Option<Self> {
        if let Some(handle) = ResourceStore::get_resource(&key) {
            Some(Resource {
                handle: handle,
                key: key,
            })
        } else {
            None
        }
    }
}

/// A value that can be implicitly constructed given a key.
pub trait Loadable<K = String> {
    fn load(_key: &K) -> Option<Self>
        where Self: Sized
    {
        // Default implementation so that types with no load semantics can be used with
        // ResourceCache so that all inserts must be explicit.
        None
    }
}

/// A cache that associates resource values with paths.
///
/// Resources and paths are assumed to be immutable.
pub struct ResourceCache<T, K = String> {
    cache: HashMap<K, Arc<T>>,
}

impl<K: Eq + hash::Hash + Clone, T: Loadable<K>> ResourceCache<T, K> {
    pub fn new() -> ResourceCache<T, K> { ResourceCache { cache: HashMap::new() } }

    pub fn get(&mut self, key: &K) -> Option<Arc<T>> {
        if let Some(v) = self.cache.get(key) {
            return Some(v.clone());
        }

        if let Some(v) = T::load(key) {
            let v = Arc::new(v);
            self.cache.insert(key.clone(), v.clone());
            Some(v)
        } else {
            None
        }
    }

    pub fn insert(&mut self, key: K, value: T) { self.cache.insert(key, Arc::new(value)); }
}

/// Implement a thread-local store for a given resource type.
///
/// Name is the identifier for the store, key and value are the types of the resource cache keys
/// and the resources.
///
///     # #[macro_use] extern crate calx_resource;
///     use calx_resource::{Resource, ResourceStore, Loadable};
///
///     // A custom resource type.
///     struct MyResource { pub text: String }
///
///     // Must be present even if there's no specific implementation.
///     impl Loadable for MyResource {}
///
///     // Generate a resource store.
///     impl_store!(MY_RESOURCE_STORE, String, MyResource);
///
///     fn main() {
///         // Save a resource in the store using a key.
///         MyResource::insert_resource(
///             "test_resource".to_string(),
///             MyResource { text: "Hello, world!".to_string() });
///
///         // Fetch a resource handle from the store using our key.
///         let handle: Resource<MyResource> =
///             Resource::new("test_resource".to_string()).unwrap();
///         assert!(&handle.text == "Hello, world!");
///     }
#[macro_export]
macro_rules! impl_store {
    ($name:ident, $key:ty, $value:ty) => {
    thread_local!(static $name: ::std::cell::RefCell<$crate::ResourceCache<$value, $key>> =
                  ::std::cell::RefCell::new($crate::ResourceCache::new()));

    impl $crate::ResourceStore<$key> for $value {
        fn get_resource(key: &$key) -> Option<::std::sync::Arc<Self>> {
            $name.with(|t| t.borrow_mut().get(key))
        }

        fn insert_resource(key: $key, value: $value) {
            $name.with(|t| t.borrow_mut().insert(key, value));
        }
    }}
}
<|endoftext|>


<commit_before>//! WebAssembly interpreter module.

use std::any::TypeId;

/// Custom user error.
pub trait UserError: 'static + ::std::fmt::Display + ::std::fmt::Debug {
	#[doc(hidden)]
	fn __private_get_type_id__(&self) -> TypeId {
		TypeId::of::<Self>()
	}
}

impl UserError {
	/// Attempt to downcast this `UserError` to a concrete type by reference.
	pub fn downcast_ref<T: UserError>(&self) -> Option<&T> {
		if self.__private_get_type_id__() == TypeId::of::<T>() {
			unsafe { Some(&*(self as *const UserError as *const T)) }
		} else {
			None
		}
	}

	/// Attempt to downcast this `UserError` to a concrete type by mutable
	/// reference.
	pub fn downcast_mut<T: UserError>(&mut self) -> Option<&mut T> {
		if self.__private_get_type_id__() == TypeId::of::<T>() {
			unsafe { Some(&mut *(self as *mut UserError as *mut T)) }
		} else {
			None
		}
	}
}

/// Internal interpreter error.
#[derive(Debug)]
pub enum Error {
	/// Program-level error.
	Program(String),
	/// Validation error.
	Validation(String),
	/// Initialization error.
	Initialization(String),
	/// Function-level error.
	Function(String),
	/// Table-level error.
	Table(String),
	/// Memory-level error.
	Memory(String),
	/// Variable-level error.
	Variable(String),
	/// Global-level error.
	Global(String),
	/// Local-level error.
	Local(String),
	/// Stack-level error.
	Stack(String),
	/// Value-level error.
	Value(String),
	/// Interpreter (code) error.
	Interpreter(String),
	/// Env module error.
	Env(String),
	/// Native module error.
	Native(String),
	/// Trap.
	Trap(String),
	/// Custom user error.
	User(Box<UserError>),
}

impl Into<String> for Error {
	fn into(self) -> String {
		match self {
			Error::Program(s) => s,
			Error::Validation(s) => s,
			Error::Initialization(s) => s,
			Error::Function(s) => s,
			Error::Table(s) => s,
			Error::Memory(s) => s,
			Error::Variable(s) => s,
			Error::Global(s) => s,
			Error::Local(s) => s,
			Error::Stack(s) => s,
			Error::Interpreter(s) => s,
			Error::Value(s) => s,
			Error::Env(s) => s,
			Error::Native(s) => s,
			Error::Trap(s) => format!("trap: {}", s),
			Error::User(e) => format!("user: {}", e),
		}
	}
}

impl ::std::fmt::Display for Error {
	fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
		match *self {
			Error::Program(ref s) => write!(f, "Program: {}", s),
			Error::Validation(ref s) => write!(f, "Validation: {}", s),
			Error::Initialization(ref s) => write!(f, "Initialization: {}", s),
			Error::Function(ref s) => write!(f, "Function: {}", s),
			Error::Table(ref s) => write!(f, "Table: {}", s),
			Error::Memory(ref s) => write!(f, "Memory: {}", s),
			Error::Variable(ref s) => write!(f, "Variable: {}", s),
			Error::Global(ref s) => write!(f, "Global: {}", s),
			Error::Local(ref s) => write!(f, "Local: {}", s),
			Error::Stack(ref s) => write!(f, "Stack: {}", s),
			Error::Interpreter(ref s) => write!(f, "Interpreter: {}", s),
			Error::Value(ref s) => write!(f, "Value: {}", s),
			Error::Env(ref s) => write!(f, "Env: {}", s),
			Error::Native(ref s) => write!(f, "Native: {}", s),
			Error::Trap(ref s) => write!(f, "Trap: {}", s),
			Error::User(ref e) => write!(f, "User: {}", e),
		}
	}
}

impl<U> From<U> for Error where U: UserError + Sized {
	fn from(e: U) -> Self {
		Error::User(Box::new(e))
	}
}

mod emscripten;
mod native;
mod imports;
mod memory;
mod module;
mod program;
mod runner;
mod stack;
mod table;
mod validator;
mod value;
mod variable;

#[cfg(test)]
mod tests;

pub use self::memory::MemoryInstance;
pub use self::module::{ModuleInstance, ModuleInstanceInterface,
	ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature};
pub use self::table::TableInstance;
pub use self::program::ProgramInstance;
pub use self::value::RuntimeValue;
pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue};
pub use self::native::{native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor};
pub use self::emscripten::EnvParams;
<commit_msg>Remove Env error variant<commit_after>//! WebAssembly interpreter module.

use std::any::TypeId;

/// Custom user error.
pub trait UserError: 'static + ::std::fmt::Display + ::std::fmt::Debug {
	#[doc(hidden)]
	fn __private_get_type_id__(&self) -> TypeId {
		TypeId::of::<Self>()
	}
}

impl UserError {
	/// Attempt to downcast this `UserError` to a concrete type by reference.
	pub fn downcast_ref<T: UserError>(&self) -> Option<&T> {
		if self.__private_get_type_id__() == TypeId::of::<T>() {
			unsafe { Some(&*(self as *const UserError as *const T)) }
		} else {
			None
		}
	}

	/// Attempt to downcast this `UserError` to a concrete type by mutable
	/// reference.
	pub fn downcast_mut<T: UserError>(&mut self) -> Option<&mut T> {
		if self.__private_get_type_id__() == TypeId::of::<T>() {
			unsafe { Some(&mut *(self as *mut UserError as *mut T)) }
		} else {
			None
		}
	}
}

/// Internal interpreter error.
#[derive(Debug)]
pub enum Error {
	/// Program-level error.
	Program(String),
	/// Validation error.
	Validation(String),
	/// Initialization error.
	Initialization(String),
	/// Function-level error.
	Function(String),
	/// Table-level error.
	Table(String),
	/// Memory-level error.
	Memory(String),
	/// Variable-level error.
	Variable(String),
	/// Global-level error.
	Global(String),
	/// Local-level error.
	Local(String),
	/// Stack-level error.
	Stack(String),
	/// Value-level error.
	Value(String),
	/// Interpreter (code) error.
	Interpreter(String),
	/// Native module error.
	Native(String),
	/// Trap.
	Trap(String),
	/// Custom user error.
	User(Box<UserError>),
}

impl Into<String> for Error {
	fn into(self) -> String {
		match self {
			Error::Program(s) => s,
			Error::Validation(s) => s,
			Error::Initialization(s) => s,
			Error::Function(s) => s,
			Error::Table(s) => s,
			Error::Memory(s) => s,
			Error::Variable(s) => s,
			Error::Global(s) => s,
			Error::Local(s) => s,
			Error::Stack(s) => s,
			Error::Interpreter(s) => s,
			Error::Value(s) => s,
			Error::Native(s) => s,
			Error::Trap(s) => format!("trap: {}", s),
			Error::User(e) => format!("user: {}", e),
		}
	}
}

impl ::std::fmt::Display for Error {
	fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
		match *self {
			Error::Program(ref s) => write!(f, "Program: {}", s),
			Error::Validation(ref s) => write!(f, "Validation: {}", s),
			Error::Initialization(ref s) => write!(f, "Initialization: {}", s),
			Error::Function(ref s) => write!(f, "Function: {}", s),
			Error::Table(ref s) => write!(f, "Table: {}", s),
			Error::Memory(ref s) => write!(f, "Memory: {}", s),
			Error::Variable(ref s) => write!(f, "Variable: {}", s),
			Error::Global(ref s) => write!(f, "Global: {}", s),
			Error::Local(ref s) => write!(f, "Local: {}", s),
			Error::Stack(ref s) => write!(f, "Stack: {}", s),
			Error::Interpreter(ref s) => write!(f, "Interpreter: {}", s),
			Error::Value(ref s) => write!(f, "Value: {}", s),
			Error::Native(ref s) => write!(f, "Native: {}", s),
			Error::Trap(ref s) => write!(f, "Trap: {}", s),
			Error::User(ref e) => write!(f, "User: {}", e),
		}
	}
}

impl<U> From<U> for Error where U: UserError + Sized {
	fn from(e: U) -> Self {
		Error::User(Box::new(e))
	}
}

mod emscripten;
mod native;
mod imports;
mod memory;
mod module;
mod program;
mod runner;
mod stack;
mod table;
mod validator;
mod value;
mod variable;

#[cfg(test)]
mod tests;

pub use self::memory::MemoryInstance;
pub use self::module::{ModuleInstance, ModuleInstanceInterface,
	ItemIndex, ExportEntryType, CallerContext, ExecutionParams, FunctionSignature};
pub use self::table::TableInstance;
pub use self::program::ProgramInstance;
pub use self::value::RuntimeValue;
pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue};
pub use self::native::{native_module, UserDefinedElements, UserFunctionExecutor, UserFunctionDescriptor};
pub use self::emscripten::EnvParams;
<|endoftext|>


<commit_before>use rustc::hir::def_id::DefId;
use rustc::ty::layout::Layout;
use rustc::ty::subst::{Substs, Kind};
use rustc::ty::{self, Ty};
use rustc::mir;
use syntax::codemap::Span;

use error::{EvalError, EvalResult};
use eval_context::{EvalContext, monomorphize_field_ty, StackPopCleanup};
use lvalue::{Lvalue, LvalueExtra};
use memory::Pointer;
use value::PrimVal;
use value::Value;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {

    /// Creates stack frames for all drop impls. See `drop` for the actual content.
    pub fn eval_drop_impls(&mut self, drops: Vec<(DefId, Value, &'tcx Substs<'tcx>)>, span: Span) -> EvalResult<'tcx> {
        // add them to the stack in reverse order, because the impl that needs to run the last
        // is the one that needs to be at the bottom of the stack
        for (drop_def_id, self_arg, substs) in drops.into_iter().rev() {
            let mir = self.load_mir(drop_def_id)?;
            trace!("substs for drop glue: {:?}", substs);
            self.push_stack_frame(
                drop_def_id,
                span,
                mir,
                substs,
                Lvalue::from_ptr(Pointer::zst_ptr()),
                StackPopCleanup::None,
                Vec::new(),
            )?;
            let mut arg_locals = self.frame().mir.args_iter();
            let first = arg_locals.next().expect("drop impl has self arg");
            assert!(arg_locals.next().is_none(), "drop impl should have only one arg");
            let dest = self.eval_lvalue(&mir::Lvalue::Local(first))?;
            let ty = self.frame().mir.local_decls[first].ty;
            self.write_value(self_arg, dest, ty)?;
        }
        Ok(())
    }

    /// push DefIds of drop impls and their argument on the given vector
    pub fn drop(
        &mut self,
        lval: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx> {
        if !self.type_needs_drop(ty) {
            debug!("no need to drop {:?}", ty);
            return Ok(());
        }
        trace!("-need to drop {:?} at {:?}", ty, lval);

        match ty.sty {
            // special case `Box` to deallocate the inner allocation
            ty::TyAdt(ref def, _) if def.is_box() => {
                let contents_ty = ty.boxed_ty();
                let val = self.read_lvalue(lval);
                // we are going through the read_value path, because that already does all the
                // checks for the trait object types. We'd only be repeating ourselves here.
                let val = self.follow_by_ref_value(val, ty)?;
                trace!("box dealloc on {:?}", val);
                match val {
                    Value::ByRef(_) => bug!("follow_by_ref_value can't result in ByRef"),
                    Value::ByVal(ptr) => {
                        assert!(self.type_is_sized(contents_ty));
                        let contents_ptr = ptr.to_ptr()?;
                        self.drop(Lvalue::from_ptr(contents_ptr), contents_ty, drop)?;
                    },
                    Value::ByValPair(prim_ptr, extra) => {
                        let ptr = prim_ptr.to_ptr()?;
                        let extra = match self.tcx.struct_tail(contents_ty).sty {
                            ty::TyDynamic(..) => LvalueExtra::Vtable(extra.to_ptr()?),
                            ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.to_u64()?),
                            _ => bug!("invalid fat pointer type: {}", ty),
                        };
                        self.drop(Lvalue::Ptr { ptr, extra }, contents_ty, drop)?;
                    },
                }
                // We cannot use Box's destructor, because it is a no-op and only exists to reduce
                // the number of hacks required in the compiler around the Box type.
                let box_free_fn = self.tcx.lang_items.box_free_fn().expect("no box_free lang item");
                let substs = self.tcx.intern_substs(&[Kind::from(contents_ty)]);
                // this is somewhat hacky, but hey, there's no representation difference between
                // pointers, `Box`es and references, so
                // #[lang = "box_free"] unsafe fn box_free<T>(ptr: *mut T)
                // is the same as
                // fn drop(&mut self) if Self is Box<T>
                drop.push((box_free_fn, val, substs));
            },

            ty::TyAdt(adt_def, substs) => {
                // FIXME: some structs are represented as ByValPair
                let mut lval = self.force_allocation(lval)?;
                let adt_ptr = match lval {
                    Lvalue::Ptr { ptr, .. } => ptr,
                    _ => bug!("force allocation can only yield Lvalue::Ptr"),
                };
                // run drop impl before the fields' drop impls
                if let Some(drop_def_id) = adt_def.destructor() {
                    drop.push((drop_def_id, Value::ByVal(PrimVal::Ptr(adt_ptr)), substs));
                }
                let layout = self.type_layout(ty)?;
                let fields = match *layout {
                    Layout::Univariant { .. } => &adt_def.struct_variant().fields,
                    Layout::General { .. } => {
                        let discr_val = self.read_discriminant_value(adt_ptr, ty)? as u128;
                        let ptr = self.force_allocation(lval)?.to_ptr();
                        match adt_def.variants.iter().position(|v| discr_val == v.disr_val.to_u128_unchecked()) {
                            Some(i) => {
                                lval = Lvalue::Ptr {
                                    ptr,
                                    extra: LvalueExtra::DowncastVariant(i),
                                };
                                &adt_def.variants[i].fields
                            },
                            None => return Err(EvalError::InvalidDiscriminant),
                        }
                    },
                    Layout::StructWrappedNullablePointer { nndiscr, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            &adt_def.variants[discr as usize].fields
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::RawNullablePointer { nndiscr, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            assert_eq!(adt_def.variants[discr as usize].fields.len(), 1);
                            let field_ty = &adt_def.variants[discr as usize].fields[0];
                            let field_ty = monomorphize_field_ty(self.tcx, field_ty, substs);
                            // FIXME: once read_discriminant_value works with lvalue, don't force
                            // alloc in the RawNullablePointer case
                            self.drop(lval, field_ty, drop)?;
                            return Ok(());
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::CEnum { .. } => return Ok(()),
                    _ => bug!("{:?} is not an adt layout", layout),
                };
                let tcx = self.tcx;
                self.drop_fields(
                    fields.iter().map(|field| monomorphize_field_ty(tcx, field, substs)),
                    lval,
                    ty,
                    drop,
                )?;
            },
            ty::TyTuple(fields, _) => self.drop_fields(fields.into_iter().cloned(), lval, ty, drop)?,
            ty::TyDynamic(..) => {
                let (ptr, vtable) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable) } => (ptr, vtable),
                    _ => bug!("expected an lvalue with a vtable"),
                };
                let drop_fn = self.memory.read_ptr(vtable)?;
                // some values don't need to call a drop impl, so the value is null
                if drop_fn != Pointer::from_int(0) {
                    let real_ty = self.memory.get_fn(drop_fn.alloc_id)?.expect_drop_glue_real_ty()?;
                    self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?;
                } else {
                    // just a sanity check
                    assert_eq!(drop_fn.offset, 0);
                }
            },
            ty::TySlice(elem_ty) => {
                let (ptr, len) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => (ptr, len),
                    _ => bug!("expected an lvalue with a length"),
                };
                let size = self.type_size(elem_ty)?.expect("slice element must be sized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..len {
                    self.drop(Lvalue::from_ptr(ptr.offset(i * size)), elem_ty, drop)?;
                }
            },
            ty::TyArray(elem_ty, len) => {
                let lval = self.force_allocation(lval)?;
                let (ptr, extra) = match lval {
                    Lvalue::Ptr { ptr, extra } => (ptr, extra),
                    _ => bug!("expected an lvalue with optional extra data"),
                };
                let size = self.type_size(elem_ty)?.expect("array element cannot be unsized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..(len as u64) {
                    self.drop(Lvalue::Ptr { ptr: ptr.offset(i * size), extra }, elem_ty, drop)?;
                }
            },
            // FIXME: what about TyClosure and TyAnon?
            // other types do not need to process drop
            _ => {},
        }

        Ok(())
    }

    fn drop_fields<I>(
        &mut self,
        fields: I,
        lval: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx>
        where I: Iterator<Item=Ty<'tcx>>,
    {
        trace!("drop_fields: {:?} of type {}", lval, ty);
        for (i, field_ty) in fields.enumerate() {
            let field_lval = self.lvalue_field(lval, i, ty, field_ty)?;
            self.drop(field_lval, field_ty, drop)?;
        }
        Ok(())
    }

    fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
        self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment())
    }
}
<commit_msg>Resolve Drop impls to get the right substs.<commit_after>use rustc::hir::def_id::DefId;
use rustc::traits;
use rustc::ty::layout::Layout;
use rustc::ty::subst::{Substs, Kind};
use rustc::ty::{self, Ty};
use rustc::mir;
use syntax::codemap::Span;

use error::{EvalError, EvalResult};
use eval_context::{EvalContext, monomorphize_field_ty, StackPopCleanup};
use lvalue::{Lvalue, LvalueExtra};
use memory::Pointer;
use value::PrimVal;
use value::Value;

impl<'a, 'tcx> EvalContext<'a, 'tcx> {
    /// Creates stack frames for all drop impls. See `drop` for the actual content.
    pub fn eval_drop_impls(&mut self, drops: Vec<(DefId, Value, &'tcx Substs<'tcx>)>, span: Span) -> EvalResult<'tcx> {
        // add them to the stack in reverse order, because the impl that needs to run the last
        // is the one that needs to be at the bottom of the stack
        for (drop_def_id, self_arg, substs) in drops.into_iter().rev() {
            let mir = self.load_mir(drop_def_id)?;
            trace!("substs for drop glue: {:?}", substs);
            self.push_stack_frame(
                drop_def_id,
                span,
                mir,
                substs,
                Lvalue::from_ptr(Pointer::zst_ptr()),
                StackPopCleanup::None,
                Vec::new(),
            )?;
            let mut arg_locals = self.frame().mir.args_iter();
            let first = arg_locals.next().expect("drop impl has self arg");
            assert!(arg_locals.next().is_none(), "drop impl should have only one arg");
            let dest = self.eval_lvalue(&mir::Lvalue::Local(first))?;
            let ty = self.frame().mir.local_decls[first].ty;
            self.write_value(self_arg, dest, ty)?;
        }
        Ok(())
    }

    /// push DefIds of drop impls and their argument on the given vector
    pub fn drop(
        &mut self,
        lval: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx> {
        if !self.type_needs_drop(ty) {
            debug!("no need to drop {:?}", ty);
            return Ok(());
        }
        trace!("-need to drop {:?} at {:?}", ty, lval);

        match ty.sty {
            // special case `Box` to deallocate the inner allocation
            ty::TyAdt(ref def, _) if def.is_box() => {
                let contents_ty = ty.boxed_ty();
                let val = self.read_lvalue(lval);
                // we are going through the read_value path, because that already does all the
                // checks for the trait object types. We'd only be repeating ourselves here.
                let val = self.follow_by_ref_value(val, ty)?;
                trace!("box dealloc on {:?}", val);
                match val {
                    Value::ByRef(_) => bug!("follow_by_ref_value can't result in ByRef"),
                    Value::ByVal(ptr) => {
                        assert!(self.type_is_sized(contents_ty));
                        let contents_ptr = ptr.to_ptr()?;
                        self.drop(Lvalue::from_ptr(contents_ptr), contents_ty, drop)?;
                    },
                    Value::ByValPair(prim_ptr, extra) => {
                        let ptr = prim_ptr.to_ptr()?;
                        let extra = match self.tcx.struct_tail(contents_ty).sty {
                            ty::TyDynamic(..) => LvalueExtra::Vtable(extra.to_ptr()?),
                            ty::TyStr | ty::TySlice(_) => LvalueExtra::Length(extra.to_u64()?),
                            _ => bug!("invalid fat pointer type: {}", ty),
                        };
                        self.drop(Lvalue::Ptr { ptr, extra }, contents_ty, drop)?;
                    },
                }
                // We cannot use Box's destructor, because it is a no-op and only exists to reduce
                // the number of hacks required in the compiler around the Box type.
                let box_free_fn = self.tcx.lang_items.box_free_fn().expect("no box_free lang item");
                let substs = self.tcx.intern_substs(&[Kind::from(contents_ty)]);
                // this is somewhat hacky, but hey, there's no representation difference between
                // pointers, `Box`es and references, so
                // #[lang = "box_free"] unsafe fn box_free<T>(ptr: *mut T)
                // is the same as
                // fn drop(&mut self) if Self is Box<T>
                drop.push((box_free_fn, val, substs));
            },

            ty::TyAdt(adt_def, substs) => {
                // FIXME: some structs are represented as ByValPair
                let mut lval = self.force_allocation(lval)?;
                let adt_ptr = match lval {
                    Lvalue::Ptr { ptr, .. } => ptr,
                    _ => bug!("force allocation can only yield Lvalue::Ptr"),
                };

                // run drop impl before the fields' drop impls
                if let Some(drop_def_id) = adt_def.destructor() {
                    let trait_ref = ty::Binder(ty::TraitRef {
                        def_id: self.tcx.lang_items.drop_trait().unwrap(),
                        substs: self.tcx.mk_substs_trait(ty, &[]),
                    });
                    let vtable = match self.fulfill_obligation(trait_ref) {
                        traits::VtableImpl(data) => data,
                        _ => bug!("dtor for {:?} is not an impl???", ty)
                    };
                    drop.push((drop_def_id, Value::ByVal(PrimVal::Ptr(adt_ptr)), vtable.substs));
                }

                let layout = self.type_layout(ty)?;
                let fields = match *layout {
                    Layout::Univariant { .. } => &adt_def.struct_variant().fields,
                    Layout::General { .. } => {
                        let discr_val = self.read_discriminant_value(adt_ptr, ty)? as u128;
                        let ptr = self.force_allocation(lval)?.to_ptr();
                        match adt_def.variants.iter().position(|v| discr_val == v.disr_val.to_u128_unchecked()) {
                            Some(i) => {
                                lval = Lvalue::Ptr {
                                    ptr,
                                    extra: LvalueExtra::DowncastVariant(i),
                                };
                                &adt_def.variants[i].fields
                            },
                            None => return Err(EvalError::InvalidDiscriminant),
                        }
                    },
                    Layout::StructWrappedNullablePointer { nndiscr, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            &adt_def.variants[discr as usize].fields
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::RawNullablePointer { nndiscr, .. } => {
                        let discr = self.read_discriminant_value(adt_ptr, ty)?;
                        if discr == nndiscr as u128 {
                            assert_eq!(discr as usize as u128, discr);
                            assert_eq!(adt_def.variants[discr as usize].fields.len(), 1);
                            let field_ty = &adt_def.variants[discr as usize].fields[0];
                            let field_ty = monomorphize_field_ty(self.tcx, field_ty, substs);
                            // FIXME: once read_discriminant_value works with lvalue, don't force
                            // alloc in the RawNullablePointer case
                            self.drop(lval, field_ty, drop)?;
                            return Ok(());
                        } else {
                            // FIXME: the zst variant might contain zst types that impl Drop
                            return Ok(()); // nothing to do, this is zero sized (e.g. `None`)
                        }
                    },
                    Layout::CEnum { .. } => return Ok(()),
                    _ => bug!("{:?} is not an adt layout", layout),
                };
                let tcx = self.tcx;
                self.drop_fields(
                    fields.iter().map(|field| monomorphize_field_ty(tcx, field, substs)),
                    lval,
                    ty,
                    drop,
                )?;
            },
            ty::TyTuple(fields, _) => self.drop_fields(fields.into_iter().cloned(), lval, ty, drop)?,
            ty::TyDynamic(..) => {
                let (ptr, vtable) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable) } => (ptr, vtable),
                    _ => bug!("expected an lvalue with a vtable"),
                };
                let drop_fn = self.memory.read_ptr(vtable)?;
                // some values don't need to call a drop impl, so the value is null
                if drop_fn != Pointer::from_int(0) {
                    let real_ty = self.memory.get_fn(drop_fn.alloc_id)?.expect_drop_glue_real_ty()?;
                    self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?;
                } else {
                    // just a sanity check
                    assert_eq!(drop_fn.offset, 0);
                }
            },
            ty::TySlice(elem_ty) => {
                let (ptr, len) = match lval {
                    Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => (ptr, len),
                    _ => bug!("expected an lvalue with a length"),
                };
                let size = self.type_size(elem_ty)?.expect("slice element must be sized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..len {
                    self.drop(Lvalue::from_ptr(ptr.offset(i * size)), elem_ty, drop)?;
                }
            },
            ty::TyArray(elem_ty, len) => {
                let lval = self.force_allocation(lval)?;
                let (ptr, extra) = match lval {
                    Lvalue::Ptr { ptr, extra } => (ptr, extra),
                    _ => bug!("expected an lvalue with optional extra data"),
                };
                let size = self.type_size(elem_ty)?.expect("array element cannot be unsized");
                // FIXME: this creates a lot of stack frames if the element type has
                // a drop impl
                for i in 0..(len as u64) {
                    self.drop(Lvalue::Ptr { ptr: ptr.offset(i * size), extra }, elem_ty, drop)?;
                }
            },
            // FIXME: what about TyClosure and TyAnon?
            // other types do not need to process drop
            _ => {},
        }

        Ok(())
    }

    fn drop_fields<I>(
        &mut self,
        fields: I,
        lval: Lvalue<'tcx>,
        ty: Ty<'tcx>,
        drop: &mut Vec<(DefId, Value, &'tcx Substs<'tcx>)>,
    ) -> EvalResult<'tcx>
        where I: Iterator<Item=Ty<'tcx>>,
    {
        trace!("drop_fields: {:?} of type {}", lval, ty);
        for (i, field_ty) in fields.enumerate() {
            let field_lval = self.lvalue_field(lval, i, ty, field_ty)?;
            self.drop(field_lval, field_ty, drop)?;
        }
        Ok(())
    }

    fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
        self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment())
    }
}
<|endoftext|>


<commit_before>use action::Action;
use config;
use config::action::ExecCondition;
use config::action::message::InjectMode;
use context::base::BaseContext;
use dispatcher::Response;
use dispatcher::response::ResponseSender;
use message::{Message, MessageBuilder};

use handlebars::{Context, Handlebars};
use std::borrow::Borrow;
use std::collections::BTreeMap;
use state::State;
use self::error::Error;
use self::renderer_context::RendererContext;

mod error;
mod renderer_context;
#[cfg(test)]
mod test;

pub const CONTEXT_UUID: &'static str = "context_uuid";
pub const CONTEXT_NAME: &'static str = "context_name";
pub const CONTEXT_LEN: &'static str = "context_len";
pub const MESSAGES: &'static str = "messages";
const MESSAGE: &'static str = "MESSAGE";

pub struct MessageAction {
    sender: Box<ResponseSender>,
    uuid: String,
    name: Option<String>,
    values: Handlebars,
    when: ExecCondition,
    inject_mode: InjectMode,
}

impl MessageAction {
    pub fn new(sender: Box<ResponseSender>,
               action: config::action::MessageAction)
               -> MessageAction {
        let config::action::MessageAction { uuid, name, message, mut values, when, inject_mode } =
            action;
        values.register_template(MESSAGE, message);

        MessageAction {
            sender: sender,
            uuid: uuid,
            name: name,
            values: values,
            when: when,
            inject_mode: inject_mode,
        }
    }

    fn render_value(&self, key: &String, template_context: &Context) -> Result<String, Error> {
        let mut writer = Vec::new();
        {
            try!(self.values.renderw(key, &template_context, &mut writer));
        }
        let string = try!(String::from_utf8(writer));
        Ok(string)
    }

    fn render_values(&self, template_context: &Context) -> Result<BTreeMap<String, String>, Error> {
        let mut rendered_values = BTreeMap::new();
        for (key, _) in self.values.get_templates() {
            let rendered_value = try!(self.render_value(key, &template_context));
            rendered_values.insert(key.to_string(), rendered_value);
        }
        Ok(rendered_values)
    }

    fn render_message(&self, state: &State, context: &BaseContext) -> Result<Message, Error> {
        let template_context = {
            use handlebars::Context;
            let context = RendererContext::new(state, context);
            Context::wraps(&context)
        };

        let mut rendered_values = try!(self.render_values(&template_context));
        MessageAction::extend_with_context_information(&mut rendered_values, state, context);
        let message = rendered_values.remove(MESSAGE)
                                     .expect(&format!("There is no '{}' key in the renderer \
                                                       key-value pairs",
                                                      MESSAGE));
        let name = self.name.as_ref().map(|name| name.borrow());
        let message = MessageBuilder::new(&self.uuid, message)
                          .name(name)
                          .values(rendered_values)
                          .build();
        Ok(message)
    }

    fn extend_with_context_information(values: &mut BTreeMap<String, String>,
                                       state: &State,
                                       context: &BaseContext) {
        values.insert(CONTEXT_UUID.to_string(),
                      context.uuid().to_hyphenated_string());
        values.insert(CONTEXT_LEN.to_string(), state.messages().len().to_string());
        if let Some(name) = context.name() {
            values.insert(CONTEXT_NAME.to_string(), name.to_string());
        }
    }

    fn execute(&self, _state: &State, _context: &BaseContext) {
        match self.render_message(_state, _context) {
            Ok(message) => {
                let response = Alert {
                    message: message,
                    inject_mode: self.inject_mode.clone(),
                };
                self.sender.send_response(Response::Alert(response));
            }
            Err(error) => {
                error!("{}", error);
            }
        }
    }
}

#[derive(Debug)]
pub struct Alert {
    message: Message,
    inject_mode: InjectMode,
}

impl Alert {
    pub fn message(&self) -> &Message {
        &self.message
    }
}

impl Action for MessageAction {
    fn on_opened(&self, _state: &State, _context: &BaseContext) {
        if self.when.on_opened {
            trace!("MessageAction: on_opened()");
            self.execute(_state, _context);
        }
    }

    fn on_closed(&self, _state: &State, _context: &BaseContext) {
        if self.when.on_closed {
            trace!("MessageAction: on_closed()");
            self.execute(_state, _context);
        }
    }
}
<commit_msg>action::MessageAction: embed config::action::MessageAction<commit_after>use action::Action;
use config;
use config::action::message::InjectMode;
use context::base::BaseContext;
use dispatcher::Response;
use dispatcher::response::ResponseSender;
use message::{Message, MessageBuilder};

use handlebars::Context;
use std::borrow::Borrow;
use std::collections::BTreeMap;
use state::State;
use self::error::Error;
use self::renderer_context::RendererContext;

mod error;
mod renderer_context;
#[cfg(test)]
mod test;

pub const CONTEXT_UUID: &'static str = "context_uuid";
pub const CONTEXT_NAME: &'static str = "context_name";
pub const CONTEXT_LEN: &'static str = "context_len";
pub const MESSAGES: &'static str = "messages";
const MESSAGE: &'static str = "MESSAGE";

pub struct MessageAction {
    sender: Box<ResponseSender>,
    action: config::action::MessageAction,
}

impl MessageAction {
    pub fn new(sender: Box<ResponseSender>,
               mut action: config::action::MessageAction)
               -> MessageAction {
        let message = action.message.clone();
        action.values.register_template(MESSAGE, message);

        MessageAction {
            sender: sender,
            action: action,
        }
    }

    fn render_value(&self, key: &String, template_context: &Context) -> Result<String, Error> {
        let mut writer = Vec::new();
        {
            try!(self.action.values.renderw(key, &template_context, &mut writer));
        }
        let string = try!(String::from_utf8(writer));
        Ok(string)
    }

    fn render_values(&self, template_context: &Context) -> Result<BTreeMap<String, String>, Error> {
        let mut rendered_values = BTreeMap::new();
        for (key, _) in self.action.values.get_templates() {
            let rendered_value = try!(self.render_value(key, &template_context));
            rendered_values.insert(key.to_string(), rendered_value);
        }
        Ok(rendered_values)
    }

    fn render_message(&self, state: &State, context: &BaseContext) -> Result<Message, Error> {
        let template_context = {
            use handlebars::Context;
            let context = RendererContext::new(state, context);
            Context::wraps(&context)
        };

        let mut rendered_values = try!(self.render_values(&template_context));
        MessageAction::extend_with_context_information(&mut rendered_values, state, context);
        let message = rendered_values.remove(MESSAGE)
                                     .expect(&format!("There is no '{}' key in the renderer \
                                                       key-value pairs",
                                                      MESSAGE));
        let name = self.action.name.as_ref().map(|name| name.borrow());
        let message = MessageBuilder::new(&self.action.uuid, message)
                          .name(name)
                          .values(rendered_values)
                          .build();
        Ok(message)
    }

    fn extend_with_context_information(values: &mut BTreeMap<String, String>,
                                       state: &State,
                                       context: &BaseContext) {
        values.insert(CONTEXT_UUID.to_string(),
                      context.uuid().to_hyphenated_string());
        values.insert(CONTEXT_LEN.to_string(), state.messages().len().to_string());
        if let Some(name) = context.name() {
            values.insert(CONTEXT_NAME.to_string(), name.to_string());
        }
    }

    fn execute(&self, _state: &State, _context: &BaseContext) {
        match self.render_message(_state, _context) {
            Ok(message) => {
                let response = Alert {
                    message: message,
                    inject_mode: self.action.inject_mode.clone(),
                };
                self.sender.send_response(Response::Alert(response));
            }
            Err(error) => {
                error!("{}", error);
            }
        }
    }
}

#[derive(Debug)]
pub struct Alert {
    message: Message,
    inject_mode: InjectMode,
}

impl Alert {
    pub fn message(&self) -> &Message {
        &self.message
    }
}

impl Action for MessageAction {
    fn on_opened(&self, _state: &State, _context: &BaseContext) {
        if self.action.when.on_opened {
            trace!("MessageAction: on_opened()");
            self.execute(_state, _context);
        }
    }

    fn on_closed(&self, _state: &State, _context: &BaseContext) {
        if self.action.when.on_closed {
            trace!("MessageAction: on_closed()");
            self.execute(_state, _context);
        }
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
// Copyright © 2014-2018 Miguel Peláez <kernelfreeze@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use core::resource_manager::resource::Resource;
use core::resource_manager::resource_type::ResourceType;
use core::settings::Settings;

use image;

use glium::{Display, Program};

use std::collections::HashMap;
use std::sync::Arc;

pub struct ShaderManager {
    shaders: HashMap<&'static str, Program>
}

impl ShaderManager {
    /// Start shader manager
    pub fn new() -> ShaderManager {
        info!("Starting shader manager...");

        ShaderManager {
            shaders: HashMap::new(),
        }
    }

    /// Load and build a shader
    pub fn load(&mut self, name: &'static str, settings: Arc<Settings>, display: &Display) {
        if let Some(_) = self.get(name) {
            warn!("Shader '{}' is already loaded!", name);
            return;
        }

        let v_settings = Arc::clone(&settings);

        let v_140 = Resource::litecraft_path(name, "140", ResourceType::VertexShader);
        let f_140 = Resource::litecraft_path(name, "140", ResourceType::FragmentShader);

        let v_100 = Resource::litecraft_path(name, "100", ResourceType::VertexShader);
        let f_100 = Resource::litecraft_path(name, "100", ResourceType::FragmentShader);

        let program =
            program!(display,
        140 => {
            vertex: &v_140.load(v_settings),
            fragment: &f_140.load(settings)
        },

        100 => {
            vertex: &v_100.load(v_settings),
            fragment: &f_100.load(settings)
        }).expect("Failed to build a required shader program. Do you have updated GPU drivers?");

        self.shaders.insert(name, program);
    }

    /// Get a compiled shader program
    pub fn get(&self, name: &str) -> Option<&Program> { self.shaders.get(name) }
}
<commit_msg>Fix style...<commit_after>// The MIT License (MIT)
// Copyright © 2014-2018 Miguel Peláez <kernelfreeze@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use core::resource_manager::resource::Resource;
use core::resource_manager::resource_type::ResourceType;
use core::settings::Settings;

use image;

use glium::{Display, Program};

use std::collections::HashMap;
use std::sync::Arc;

pub struct ShaderManager {
    shaders: HashMap<&'static str, Program>,
}

impl ShaderManager {
    /// Start shader manager
    pub fn new() -> ShaderManager {
        info!("Starting shader manager...");

        ShaderManager {
            shaders: HashMap::new(),
        }
    }

    /// Load and build a shader
    pub fn load(&mut self, name: &'static str, settings: Arc<Settings>, display: &Display) {
        if let Some(_) = self.get(name) {
            warn!("Shader '{}' is already loaded!", name);
            return;
        }

        let v_settings = Arc::clone(&settings);

        let v_140 = Resource::litecraft_path(name, "140", ResourceType::VertexShader);
        let f_140 = Resource::litecraft_path(name, "140", ResourceType::FragmentShader);

        let v_100 = Resource::litecraft_path(name, "100", ResourceType::VertexShader);
        let f_100 = Resource::litecraft_path(name, "100", ResourceType::FragmentShader);

        let program =
            program!(display,
        140 => {
            vertex: &v_140.load(v_settings),
            fragment: &f_140.load(settings)
        },

        100 => {
            vertex: &v_100.load(v_settings),
            fragment: &f_100.load(settings)
        }).expect("Failed to build a required shader program. Do you have updated GPU drivers?");

        self.shaders.insert(name, program);
    }

    /// Get a compiled shader program
    pub fn get(&self, name: &str) -> Option<&Program> { self.shaders.get(name) }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! # Regular patterns
//!
//! This provides a data structure, `Pattern<Symbol>` representing a matching pattern in a regular language. This is a
//! more generalised form of a regular expression as it supports symbol types other than simple strings. A pattern using
//! the `char` symbol has identical expressive power to a regular expression.
//!
//! Regular patterns can be created from strings, arrays or vectors using `into_pattern`, and can use any cloneable type
//! to represent a symbol:
//!
//! ```
//! # use ndfa::*;
//! let match_abc = "abc".into_pattern();
//! let match_123 = [1,2,3].into_pattern();
//! ```
//!
//! These patterns are quite boring (they just match exactly the string that's passed in). To create more interesting
//! patterns, there are a series of functions that will create patterns with repetitions or other constructs in them:
//!
//! ```
//! # use ndfa::*;
//! let stuff_or_nonsense = "stuff".or("nonsense");
//! let any_amount_of_stuff = "stuff".repeat_forever(1);
//! let went_to_market = "piggies".repeat(0..5);
//! ```
//!
//! For convenience, these methods will work on any type that can be converted into a pattern. Every regular expression
//! can be converted into a regular pattern, but these patterns are also for symbol types other than characters, and do
//! not require any quoting in order to be used (and are hence much easier to use with dynamic values).
//!
//! ```
//! # use ndfa::*;
//! let some_counting = vec![1, 2, 3].repeat_forever(1);
//! ```
//!

use std::iter::FromIterator;
use std::ops::Range;

use super::state_machine::*;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Pattern<Symbol: Clone> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

impl<Symbol: Clone> Pattern<Symbol> {
    ///
    /// Compiles this pattern onto a state machine, returning the accepting symbol
    ///
    pub fn compile<OutputSymbol>(&self, state_machine: &mut MutableStateMachine<Symbol, OutputSymbol>, start_state: StateId) -> StateId {
        match self {
            &Epsilon => {
                start_state
            },

            &Match(ref symbols) => {
                // Match each symbol in turn
                let mut current_state = start_state;

                for sym in symbols {
                    let next_state = state_machine.count_states();
                    state_machine.add_transition(current_state, sym.clone(), next_state);
                    current_state = next_state;
                }

                current_state
            },

            &RepeatInfinite(ref count, ref pattern) => {
                start_state
            },

            &Repeat(ref range, ref pattern) => {
                start_state
            },

            &MatchAll(ref patterns) => {
                start_state
            },

            &MatchAny(ref patterns) => {
                start_state
            }
        }
    }
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol: Clone> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol: Clone> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol: Clone> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol: Clone> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can modify existing patterns into other forms
///
/// Pattern transformers act by altering a single pattern object into a new form
///
pub trait PatternTransformer<Symbol: Clone> {
    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

///
/// Implemented by things that combine patterns together to create new patterns
///
pub trait PatternCombiner<Symbol: Clone, SecondPattern: IntoPattern<Symbol>> {
    /// Appends a pattern to this one
    fn append(self, pattern: SecondPattern) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: SecondPattern) -> Pattern<Symbol>;
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>> PatternTransformer<Symbol> for PatternType {
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self.into_pattern()))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self.into_pattern()))
    }
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>, SecondPatternType: IntoPattern<Symbol>> PatternCombiner<Symbol, SecondPatternType> for PatternType {
    fn append(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'Match(x)' and 'Match(y)' should produce 'Match(xy)'
            (Match(first_string), Match(second_string)) => Match(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (MatchAll(first_string), MatchAll(second_string)) => MatchAll(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'y' should produce 'MatchAll(xy)'
            (MatchAll(first_string), second) => {
                let mut result = first_string.clone();
                result.push(second);
                MatchAll(result)
            },

            // Combining 'x' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (first, MatchAll(second_string)) => {
                let mut result: Vec<Pattern<Symbol>> = vec![first];
                for p in second_string {
                    result.push(p.clone());
                }
                MatchAll(result)
            },

            // Everything else is just MatchAll(xy)
            (first, second) => MatchAll(vec![first, second])
        }
    }

    fn or(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'MatchAny(x)' and 'MatchAny(y)' should produce 'MatchAny(xy)'
            (MatchAny(first_string), MatchAny(second_string)) => MatchAny(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Everything else is just MatchAny(xy)
            (first, second) => MatchAny(vec![first, second])
        }
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }

    #[test]
    fn can_repeat_pattern() {
        let pattern = "abc".repeat(1..2);

        assert!(pattern == Repeat(1..2, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_repeat_pattern_forever() {
        let pattern = "abc".repeat_forever(0);

        assert!(pattern == RepeatInfinite(0, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_append_pattern_combine_matches() {
        let pattern = "abc".append("def");

        assert!(pattern == Match(vec!['a', 'b', 'c', 'd', 'e', 'f']));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_left() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append("def");

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_right() {
        let pattern = "abc".append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_both() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_not_matchall_or_match() {
        let pattern: Pattern<char> = MatchAny(vec![Epsilon]).append(MatchAny(vec![Epsilon]));

        assert!(pattern == MatchAll(vec![MatchAny(vec![Epsilon]), MatchAny(vec![Epsilon])]));
    }

    #[test]
    fn can_or_pattern() {
        let pattern = "abc".or("def");

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_or_pattern_combine_matchanys() {
        let pattern = MatchAny(vec!["abc".to_pattern()]).or(MatchAny(vec!["def".to_pattern()]));

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }
}
<commit_msg>Implement MatchAll<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! # Regular patterns
//!
//! This provides a data structure, `Pattern<Symbol>` representing a matching pattern in a regular language. This is a
//! more generalised form of a regular expression as it supports symbol types other than simple strings. A pattern using
//! the `char` symbol has identical expressive power to a regular expression.
//!
//! Regular patterns can be created from strings, arrays or vectors using `into_pattern`, and can use any cloneable type
//! to represent a symbol:
//!
//! ```
//! # use ndfa::*;
//! let match_abc = "abc".into_pattern();
//! let match_123 = [1,2,3].into_pattern();
//! ```
//!
//! These patterns are quite boring (they just match exactly the string that's passed in). To create more interesting
//! patterns, there are a series of functions that will create patterns with repetitions or other constructs in them:
//!
//! ```
//! # use ndfa::*;
//! let stuff_or_nonsense = "stuff".or("nonsense");
//! let any_amount_of_stuff = "stuff".repeat_forever(1);
//! let went_to_market = "piggies".repeat(0..5);
//! ```
//!
//! For convenience, these methods will work on any type that can be converted into a pattern. Every regular expression
//! can be converted into a regular pattern, but these patterns are also for symbol types other than characters, and do
//! not require any quoting in order to be used (and are hence much easier to use with dynamic values).
//!
//! ```
//! # use ndfa::*;
//! let some_counting = vec![1, 2, 3].repeat_forever(1);
//! ```
//!

use std::iter::FromIterator;
use std::ops::Range;

use super::state_machine::*;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Pattern<Symbol: Clone> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

impl<Symbol: Clone> Pattern<Symbol> {
    ///
    /// Compiles this pattern onto a state machine, returning the accepting symbol
    ///
    pub fn compile<OutputSymbol>(&self, state_machine: &mut MutableStateMachine<Symbol, OutputSymbol>, start_state: StateId) -> StateId {
        match self {
            &Epsilon => {
                start_state
            },

            &Match(ref symbols) => {
                // Match each symbol in turn
                let mut current_state = start_state;

                for sym in symbols {
                    let next_state = state_machine.count_states();
                    state_machine.add_transition(current_state, sym.clone(), next_state);
                    current_state = next_state;
                }

                current_state
            },

            &RepeatInfinite(ref count, ref pattern) => {
                start_state
            },

            &Repeat(ref range, ref pattern) => {
                start_state
            },

            &MatchAll(ref patterns) => {
                // Match each pattern in turn
                let mut current_state = start_state;

                for pattern in patterns {
                    let next_state = self.compile(state_machine, current_state);
                    current_state = next_state;
                }

                current_state
            },

            &MatchAny(ref patterns) => {
                start_state
            }
        }
    }
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol: Clone> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol: Clone> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol: Clone> IntoPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol: Clone> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol: Clone, PatternType: ToPattern<Symbol>> IntoPattern<Symbol> for &'a PatternType {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a, Symbol: Clone> IntoPattern<Symbol> for &'a [Symbol] {
    #[inline]
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<'a> IntoPattern<char> for &'a str {
    #[inline]
    fn into_pattern(self) -> Pattern<char> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    #[inline]
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    #[inline]
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can modify existing patterns into other forms
///
/// Pattern transformers act by altering a single pattern object into a new form
///
pub trait PatternTransformer<Symbol: Clone> {
    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

///
/// Implemented by things that combine patterns together to create new patterns
///
pub trait PatternCombiner<Symbol: Clone, SecondPattern: IntoPattern<Symbol>> {
    /// Appends a pattern to this one
    fn append(self, pattern: SecondPattern) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: SecondPattern) -> Pattern<Symbol>;
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>> PatternTransformer<Symbol> for PatternType {
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self.into_pattern()))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self.into_pattern()))
    }
}

impl<Symbol: Clone, PatternType: IntoPattern<Symbol>, SecondPatternType: IntoPattern<Symbol>> PatternCombiner<Symbol, SecondPatternType> for PatternType {
    fn append(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'Match(x)' and 'Match(y)' should produce 'Match(xy)'
            (Match(first_string), Match(second_string)) => Match(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (MatchAll(first_string), MatchAll(second_string)) => MatchAll(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Combining 'MatchAll(x)' and 'y' should produce 'MatchAll(xy)'
            (MatchAll(first_string), second) => {
                let mut result = first_string.clone();
                result.push(second);
                MatchAll(result)
            },

            // Combining 'x' and 'MatchAll(y)' should produce 'MatchAll(xy)'
            (first, MatchAll(second_string)) => {
                let mut result: Vec<Pattern<Symbol>> = vec![first];
                for p in second_string {
                    result.push(p.clone());
                }
                MatchAll(result)
            },

            // Everything else is just MatchAll(xy)
            (first, second) => MatchAll(vec![first, second])
        }
    }

    fn or(self, pattern: SecondPatternType) -> Pattern<Symbol> {
        // Get the two patterns to combine
        let first_pattern   = self.into_pattern();
        let second_pattern  = pattern.into_pattern();

        // Combination rules depend on what the patterns are
        match (first_pattern, second_pattern) {
            // Combining 'MatchAny(x)' and 'MatchAny(y)' should produce 'MatchAny(xy)'
            (MatchAny(first_string), MatchAny(second_string)) => MatchAny(first_string.into_iter().chain(second_string.into_iter()).collect()),

            // Everything else is just MatchAny(xy)
            (first, second) => MatchAny(vec![first, second])
        }
    }
}

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

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].into_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".into_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }

    #[test]
    fn can_repeat_pattern() {
        let pattern = "abc".repeat(1..2);

        assert!(pattern == Repeat(1..2, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_repeat_pattern_forever() {
        let pattern = "abc".repeat_forever(0);

        assert!(pattern == RepeatInfinite(0, Box::new(Match(vec!['a', 'b', 'c']))));
    }

    #[test]
    fn can_append_pattern_combine_matches() {
        let pattern = "abc".append("def");

        assert!(pattern == Match(vec!['a', 'b', 'c', 'd', 'e', 'f']));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_left() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append("def");

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_right() {
        let pattern = "abc".append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_matchalls_both() {
        let pattern = MatchAll(vec!["abc".to_pattern()]).append(MatchAll(vec!["def".to_pattern()]));

        assert!(pattern == MatchAll(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_append_pattern_combine_not_matchall_or_match() {
        let pattern: Pattern<char> = MatchAny(vec![Epsilon]).append(MatchAny(vec![Epsilon]));

        assert!(pattern == MatchAll(vec![MatchAny(vec![Epsilon]), MatchAny(vec![Epsilon])]));
    }

    #[test]
    fn can_or_pattern() {
        let pattern = "abc".or("def");

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }

    #[test]
    fn can_or_pattern_combine_matchanys() {
        let pattern = MatchAny(vec!["abc".to_pattern()]).or(MatchAny(vec!["def".to_pattern()]));

        assert!(pattern == MatchAny(vec![Match(vec!['a', 'b', 'c']), Match(vec!['d', 'e', 'f'])]));
    }
}
<|endoftext|>


<commit_before>use definitions::ImageBuilder;
use definitions::error::*;
use definitions::typedef::*;
use mnemonic::Mnemonic;
use regex::Regex;
use std::collections::HashMap;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;

lazy_static! {
    static ref LABELED_MNEMONIC_RE: Regex = Regex::new(r"^\.(.+?) +?(.+)$").unwrap();
    static ref LABEL_RE: Regex = Regex::new(r"^\.([^\s]+)$").unwrap();
}

pub fn compile(file: File) -> Result<ImageData> {
    let reader = BufReader::new(file);

    let mut builder = ImageBuilder::new();

    let mut label_addr_map = HashMap::new();

    let mut mnemonic_vector = Vec::new();

    let mut instruction_count = 0;

    for line in reader.lines() {
        let line = line.chain_err(|| "unable to read line")?;

        if line.is_empty() {
            continue;
        }

        if let Some(first_half) = line.rsplitn(2, ';').next() {
            let first_half = first_half.trim();

            let first_half: String = if LABELED_MNEMONIC_RE.is_match(first_half) {
                let captures =
                    if let Some(captures) = LABELED_MNEMONIC_RE.captures_iter(first_half).next() {
                        captures
                    } else {
                        bail!("no label capture found")
                    };

                let label = captures[1].trim();

                println!("Label {:?} found at address {}", label, instruction_count);

                label_addr_map.entry(label.to_owned()).or_insert(instruction_count);

                captures[2].trim().to_owned()
            } else if LABEL_RE.is_match(first_half) {
                let captures = if let Some(captures) = LABEL_RE.captures_iter(first_half).next() {
                    captures
                } else {
                    bail!("no label capture found")
                };

                let label = captures[1].trim();

                println!("Label {:?} found at address {}", label, instruction_count);

                label_addr_map.entry(label.to_owned()).or_insert(instruction_count);
                continue;
            } else {
                first_half.to_owned()
            };

            let mut first_half_split = first_half.splitn(2, ' ');

            if let Some(opcode) = first_half_split.next() {
                let opcode = opcode.trim().to_lowercase();

                let args: Vec<String> = if let Some(args) = first_half_split.next() {
                    args.split(',').map(|arg| arg.trim().to_owned()).collect()
                } else {
                    Vec::new()
                };

                println!("Adding mnemonic {} with args: {:?}", opcode, args);

                mnemonic_vector.push(text_to_mnemonic(opcode, args)?);

                instruction_count += 1;
            } else {
                bail!("opcode expected. Found {:?}", first_half_split);
            }
        } else {
            bail!("instruction expected. Found {:?}", line.to_string());
        }
    }

    for mnemonic in mnemonic_vector {
        compile_mnemonic(&mut builder, mnemonic.clone(), &label_addr_map)?;
    }

    Ok(builder.gen())
}

fn text_to_mnemonic(opcode: String, args: Vec<String>) -> Result<Mnemonic> {
    match opcode.as_str() {
        "add" => Ok(Mnemonic::Add(args[0].parse()?, args[1].parse()?)),
        "sub" => Ok(Mnemonic::Sub(args[0].parse()?, args[1].parse()?)),
        "div" => Ok(Mnemonic::Div(args[0].parse()?, args[1].parse()?)),
        "mul" => Ok(Mnemonic::Mul(args[0].parse()?, args[1].parse()?)),
        "rem" => Ok(Mnemonic::Rem(args[0].parse()?, args[1].parse()?)),

        "cmp" => Ok(Mnemonic::Cmp(args[0].parse()?, args[1].parse()?)),
        "jmp" => Ok(Mnemonic::Jmp(args[0].parse()?)),
        "jmplt" => Ok(Mnemonic::JmpLt(args[0].parse()?)),
        "jmpgt" => Ok(Mnemonic::JmpGt(args[0].parse()?)),
        "jmpeq" => Ok(Mnemonic::JmpEq(args[0].parse()?)),
        "jmplteq" => Ok(Mnemonic::JmpLtEq(args[0].parse()?)),
        "jmpgteq" => Ok(Mnemonic::JmpGtEq(args[0].parse()?)),

        "cast" => Ok(Mnemonic::Cast(args[0].parse()?, args[1].parse()?)),
        "push" => Ok(Mnemonic::Push(args[0].parse()?, args[1].parse()?)),
        "mov" => Ok(Mnemonic::Mov(args[0].parse()?, args[1].parse()?)),
        "swp" => Ok(Mnemonic::Swp(args[0].parse()?, args[1].parse()?)),
        "dup" => Ok(Mnemonic::Dup(args[0].parse()?)),

        "call" => Ok(Mnemonic::Call(args[0].parse()?)),
        "ret" => Ok(Mnemonic::Ret),

        "halt" => Ok(Mnemonic::Halt),
        "pause" => Ok(Mnemonic::Pause),
        "nop" => Ok(Mnemonic::Nop),
        "int" => Ok(Mnemonic::Int(args[0].parse()?)),
        _ => bail!("unkwnown opcode {:?}", opcode),
    }
}

fn compile_mnemonic(builder: &mut ImageBuilder, mnemonic: Mnemonic, lookup: &HashMap<String, Address>)
    -> Result<()> {

    println!("Compiling mnemonic {:?}", mnemonic);

    match mnemonic {
        Mnemonic::Add(dest, src) => builder.add(dest, src),
        Mnemonic::Sub(dest, src) => builder.sub(dest, src),
        Mnemonic::Div(dest, src) => builder.div(dest, src),
        Mnemonic::Mul(dest, src) => builder.mul(dest, src),
        Mnemonic::Rem(dest, src) => builder.rem(dest, src),

        Mnemonic::Cmp(target_a, target_b) => builder.cmp(target_a, target_b),
        Mnemonic::Jmp(label) => builder.jmp(lookup[&label]),
        Mnemonic::JmpLt(label) => builder.jmp_lt(lookup[&label]),
        Mnemonic::JmpGt(label) => builder.jmp_gt(lookup[&label]),
        Mnemonic::JmpEq(label) => builder.jmp_eq(lookup[&label]),
        Mnemonic::JmpLtEq(label) => builder.jmp_lt_eq(lookup[&label]),
        Mnemonic::JmpGtEq(label) => builder.jmp_gt(lookup[&label]),

        Mnemonic::Cast(target, type_t) => builder.cast(target, type_t),

        Mnemonic::Push(target, value) => builder.push(target, value),
        Mnemonic::Mov(dest, src) => builder.mov(dest, src),
        Mnemonic::Swp(target_a, target_b) => builder.swp(target_a, target_b),
        Mnemonic::Dup(target) => builder.dup(target),

        Mnemonic::Call(label) => builder.call(lookup[&label]),
        Mnemonic::Ret => builder.ret(),

        Mnemonic::Halt => builder.halt(),
        Mnemonic::Pause => builder.pause(),
        Mnemonic::Nop => builder.nop(),
        Mnemonic::Int(int) => builder.int(int),
    }

    Ok(())
}

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

    #[test]
    fn labeled_mnemonic_regex() {
        let input = ".start mov $st, $vi(19)";

        if !LABELED_MNEMONIC_RE.is_match(input) {
            panic!("input doesn't match a labeled mnemonic");
        } else {
            let captures = LABELED_MNEMONIC_RE.captures_iter(input).next().unwrap();

            assert_eq!(captures[1].trim(), "start");
            assert_eq!(captures[2].trim(), "mov $st, $vi(19)");
        }
    }

    #[test]
    fn label_regex() {
        let input = ".start";

        if !LABEL_RE.is_match(input) {
            panic!("input doesn't match a label");
        } else {
            let captures = LABEL_RE.captures_iter(input).next().unwrap();

            assert_eq!(captures[1].trim(), "start");
        }
    }
}
<commit_msg>Secured label lookup<commit_after>use definitions::ImageBuilder;
use definitions::error::*;
use definitions::typedef::*;
use mnemonic::Mnemonic;
use regex::Regex;
use std::collections::HashMap;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;

lazy_static! {
    static ref LABELED_MNEMONIC_RE: Regex = Regex::new(r"^\.(.+?) +?(.+)$").unwrap();
    static ref LABEL_RE: Regex = Regex::new(r"^\.([^\s]+)$").unwrap();
}

pub fn compile(file: File) -> Result<ImageData> {
    let reader = BufReader::new(file);

    let mut builder = ImageBuilder::new();

    let mut label_addr_map = HashMap::new();

    let mut mnemonic_vector = Vec::new();

    let mut instruction_count = 0;

    for line in reader.lines() {
        let line = line.chain_err(|| "unable to read line")?;

        if line.is_empty() {
            continue;
        }

        if let Some(first_half) = line.rsplitn(2, ';').next() {
            let first_half = first_half.trim();

            let first_half: String = if LABELED_MNEMONIC_RE.is_match(first_half) {
                let captures =
                    if let Some(captures) = LABELED_MNEMONIC_RE.captures_iter(first_half).next() {
                        captures
                    } else {
                        bail!("no label capture found")
                    };

                let label = captures[1].trim();

                println!("Label {:?} found at address {}", label, instruction_count);

                label_addr_map.entry(label.to_owned()).or_insert(instruction_count);

                captures[2].trim().to_owned()
            } else if LABEL_RE.is_match(first_half) {
                let captures = if let Some(captures) = LABEL_RE.captures_iter(first_half).next() {
                    captures
                } else {
                    bail!("no label capture found")
                };

                let label = captures[1].trim();

                println!("Label {:?} found at address {}", label, instruction_count);

                label_addr_map.entry(label.to_owned()).or_insert(instruction_count);
                continue;
            } else {
                first_half.to_owned()
            };

            let mut first_half_split = first_half.splitn(2, ' ');

            if let Some(opcode) = first_half_split.next() {
                let opcode = opcode.trim().to_lowercase();

                let args: Vec<String> = if let Some(args) = first_half_split.next() {
                    args.split(',').map(|arg| arg.trim().to_owned()).collect()
                } else {
                    Vec::new()
                };

                println!("Adding mnemonic {} with args: {:?}", opcode, args);

                mnemonic_vector.push(text_to_mnemonic(opcode, args)?);

                instruction_count += 1;
            } else {
                bail!("opcode expected. Found {:?}", first_half_split);
            }
        } else {
            bail!("instruction expected. Found {:?}", line.to_string());
        }
    }

    for mnemonic in mnemonic_vector {
        compile_mnemonic(&mut builder, mnemonic.clone(), &label_addr_map)?;
    }

    Ok(builder.gen())
}

fn text_to_mnemonic(opcode: String, args: Vec<String>) -> Result<Mnemonic> {
    match opcode.as_str() {
        "add" => Ok(Mnemonic::Add(args[0].parse()?, args[1].parse()?)),
        "sub" => Ok(Mnemonic::Sub(args[0].parse()?, args[1].parse()?)),
        "div" => Ok(Mnemonic::Div(args[0].parse()?, args[1].parse()?)),
        "mul" => Ok(Mnemonic::Mul(args[0].parse()?, args[1].parse()?)),
        "rem" => Ok(Mnemonic::Rem(args[0].parse()?, args[1].parse()?)),

        "cmp" => Ok(Mnemonic::Cmp(args[0].parse()?, args[1].parse()?)),
        "jmp" => Ok(Mnemonic::Jmp(args[0].parse()?)),
        "jmplt" => Ok(Mnemonic::JmpLt(args[0].parse()?)),
        "jmpgt" => Ok(Mnemonic::JmpGt(args[0].parse()?)),
        "jmpeq" => Ok(Mnemonic::JmpEq(args[0].parse()?)),
        "jmplteq" => Ok(Mnemonic::JmpLtEq(args[0].parse()?)),
        "jmpgteq" => Ok(Mnemonic::JmpGtEq(args[0].parse()?)),

        "cast" => Ok(Mnemonic::Cast(args[0].parse()?, args[1].parse()?)),
        "push" => Ok(Mnemonic::Push(args[0].parse()?, args[1].parse()?)),
        "mov" => Ok(Mnemonic::Mov(args[0].parse()?, args[1].parse()?)),
        "swp" => Ok(Mnemonic::Swp(args[0].parse()?, args[1].parse()?)),
        "dup" => Ok(Mnemonic::Dup(args[0].parse()?)),

        "call" => Ok(Mnemonic::Call(args[0].parse()?)),
        "ret" => Ok(Mnemonic::Ret),

        "halt" => Ok(Mnemonic::Halt),
        "pause" => Ok(Mnemonic::Pause),
        "nop" => Ok(Mnemonic::Nop),
        "int" => Ok(Mnemonic::Int(args[0].parse()?)),
        _ => bail!("unkwnown opcode {:?}", opcode),
    }
}

fn compile_mnemonic(builder: &mut ImageBuilder, mnemonic: Mnemonic, lookup_map: &HashMap<String, Address>)
    -> Result<()> {

    println!("Compiling mnemonic {:?}", mnemonic);

    match mnemonic {
        Mnemonic::Add(dest, src) => builder.add(dest, src),
        Mnemonic::Sub(dest, src) => builder.sub(dest, src),
        Mnemonic::Div(dest, src) => builder.div(dest, src),
        Mnemonic::Mul(dest, src) => builder.mul(dest, src),
        Mnemonic::Rem(dest, src) => builder.rem(dest, src),

        Mnemonic::Cmp(target_a, target_b) => builder.cmp(target_a, target_b),
        Mnemonic::Jmp(label) => builder.jmp(lookup(lookup_map, &label)?),
        Mnemonic::JmpLt(label) => builder.jmp_lt(lookup(lookup_map, &label)?),
        Mnemonic::JmpGt(label) => builder.jmp_gt(lookup(lookup_map, &label)?),
        Mnemonic::JmpEq(label) => builder.jmp_eq(lookup(lookup_map, &label)?),
        Mnemonic::JmpLtEq(label) => builder.jmp_lt_eq(lookup(lookup_map, &label)?),
        Mnemonic::JmpGtEq(label) => builder.jmp_gt(lookup(lookup_map, &label)?),

        Mnemonic::Cast(target, type_t) => builder.cast(target, type_t),

        Mnemonic::Push(target, value) => builder.push(target, value),
        Mnemonic::Mov(dest, src) => builder.mov(dest, src),
        Mnemonic::Swp(target_a, target_b) => builder.swp(target_a, target_b),
        Mnemonic::Dup(target) => builder.dup(target),

        Mnemonic::Call(label) => builder.call(lookup(lookup_map, &label)?),
        Mnemonic::Ret => builder.ret(),

        Mnemonic::Halt => builder.halt(),
        Mnemonic::Pause => builder.pause(),
        Mnemonic::Nop => builder.nop(),
        Mnemonic::Int(int) => builder.int(int),
    }

    Ok(())
}

fn lookup(lookup: &HashMap<String, Address>, input: &String) -> Result<Address> {
    if let Some(addr) = lookup.get(input) {
        Ok(*addr)
    } else {
        bail!("label {:?} not found", input);
    }
}

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

    #[test]
    fn labeled_mnemonic_regex() {
        let input = ".start mov $st, $vi(19)";

        if !LABELED_MNEMONIC_RE.is_match(input) {
            panic!("input doesn't match a labeled mnemonic");
        } else {
            let captures = LABELED_MNEMONIC_RE.captures_iter(input).next().unwrap();

            assert_eq!(captures[1].trim(), "start");
            assert_eq!(captures[2].trim(), "mov $st, $vi(19)");
        }
    }

    #[test]
    fn label_regex() {
        let input = ".start";

        if !LABEL_RE.is_match(input) {
            panic!("input doesn't match a label");
        } else {
            let captures = LABEL_RE.captures_iter(input).next().unwrap();

            assert_eq!(captures[1].trim(), "start");
        }
    }
}
<|endoftext|>