<commit_before>//! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound
//! types until we arrive at the leaves, with custom handling for primitive types.

use std::fmt;

use rustc::ty::layout::{self, TyLayout};
use rustc::ty;
use rustc::mir::interpret::{
    EvalResult,
};

use super::{
    Machine, EvalContext, MPlaceTy, PlaceTy, OpTy,
};

// A thing that we can project into, and that has a layout.
// This wouldn't have to depend on `Machine` but with the current type inference,
// that's just more convenient to work with (avoids repeading all the `Machine` bounds).
pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
{
    // Get this value's layout.
    fn layout(&self) -> TyLayout<'tcx>;

    // Make this a `MPlaceTy`, or panic if that's not possible.
    fn force_allocation(
        self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>>;

    // Create this from an `MPlaceTy`.
    fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self;

    // Read the current enum discriminant, and downcast to that.  Also return the
    // variant index.
    fn project_downcast(
        self,
        ectx: &EvalContext<'a, 'mir, 'tcx, M>
    ) -> EvalResult<'tcx, (Self, usize)>;

    // Project to the n-th field.
    fn project_field(
        self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self>;
}

// Operands and places are both values
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
    for OpTy<'tcx, M::PointerTag>
{
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.layout
    }

    #[inline(always)]
    fn force_allocation(
        self,
        _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
        Ok(self.to_mem_place())
    }

    #[inline(always)]
    fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
        mplace.into()
    }

    #[inline(always)]
    fn project_downcast(
        self,
        ectx: &EvalContext<'a, 'mir, 'tcx, M>
    ) -> EvalResult<'tcx, (Self, usize)> {
        let idx = ectx.read_discriminant(self)?.1;
        Ok((ectx.operand_downcast(self, idx)?, idx))
    }

    #[inline(always)]
    fn project_field(
        self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self> {
        ectx.operand_field(self, field)
    }
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
    for MPlaceTy<'tcx, M::PointerTag>
{
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.layout
    }

    #[inline(always)]
    fn force_allocation(
        self,
        _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
        Ok(self)
    }

    #[inline(always)]
    fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
        mplace
    }

    #[inline(always)]
    fn project_downcast(
        self,
        ectx: &EvalContext<'a, 'mir, 'tcx, M>
    ) -> EvalResult<'tcx, (Self, usize)> {
        let idx = ectx.read_discriminant(self.into())?.1;
        Ok((ectx.mplace_downcast(self, idx)?, idx))
    }

    #[inline(always)]
    fn project_field(
        self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self> {
        ectx.mplace_field(self, field)
    }
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
    for PlaceTy<'tcx, M::PointerTag>
{
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.layout
    }

    #[inline(always)]
    fn force_allocation(
        self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
        ectx.force_allocation(self)
    }

    #[inline(always)]
    fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
        mplace.into()
    }

    #[inline(always)]
    fn project_downcast(
        self,
        ectx: &EvalContext<'a, 'mir, 'tcx, M>
    ) -> EvalResult<'tcx, (Self, usize)> {
        let idx = ectx.read_discriminant(ectx.place_to_op(self)?)?.1;
        Ok((ectx.place_downcast(self, idx)?, idx))
    }

    #[inline(always)]
    fn project_field(
        self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self> {
        ectx.place_field(self, field)
    }
}

// How to traverse a value and what to do when we are at the leaves.
pub trait ValueVisitor<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: fmt::Debug + Sized {
    type V: Value<'a, 'mir, 'tcx, M>;

    // There's a value in here.
    fn value(&self) -> &Self::V;

    // The value's layout (not meant to be overwritten).
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.value().layout()
    }

    // Replace the value by `val`, which must be the `field`th field of `self`, then call
    // `visit_value` and then un-do everything that might have happened to the visitor state.
    // The point of this is that some visitors keep a stack of fields that we projected below,
    // and this lets us avoid copying that stack; instead they will pop the stack after
    // executing `visit_value`.
    fn visit_field(
        &mut self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
        val: Self::V,
        field: usize,
    ) -> EvalResult<'tcx>;

    // A chance for the visitor to do special (different or more efficient) handling for some
    // array types.  Return `true` if the value was handled and we should return.
    #[inline]
    fn handle_array(&mut self, _ectx: &EvalContext<'a, 'mir, 'tcx, M>)
        -> EvalResult<'tcx, bool>
    {
        Ok(false)
    }

    // Execute visitor on the current value.  Used for recursing.
    #[inline]
    fn visit(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
        -> EvalResult<'tcx>
    {
        ectx.walk_value(self)
    }

    // Actions on the leaves.
    fn visit_uninhabited(&mut self, _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
        -> EvalResult<'tcx>
    { Ok(()) }
    fn visit_scalar(&mut self, _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>, _layout: &layout::Scalar)
        -> EvalResult<'tcx>
    { Ok(()) }
    fn visit_primitive(&mut self, _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
        -> EvalResult<'tcx>
    { Ok(()) }
}

impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
    pub fn walk_value<V: ValueVisitor<'a, 'mir, 'tcx, M>>(
        &mut self,
        v: &mut V,
    ) -> EvalResult<'tcx> {
        trace!("walk_value: {:?}", v);

        // If this is a multi-variant layout, we have find the right one and proceed with that.
        // (No benefit from making this recursion, but it is equivalent to that.)
        match v.layout().variants {
            layout::Variants::NicheFilling { .. } |
            layout::Variants::Tagged { .. } => {
                let (inner, idx) = v.value().project_downcast(self)?;
                trace!("variant layout: {:#?}", inner.layout());
                // recurse with the inner type
                return v.visit_field(self, inner, idx);
            }
            layout::Variants::Single { .. } => {}
        }

        // Even for single variants, we might be able to get a more refined type:
        // If it is a trait object, switch to the actual type that was used to create it.
        match v.layout().ty.sty {
            ty::Dynamic(..) => {
                // immediate trait objects are not a thing
                let dest = v.value().force_allocation(self)?;
                let inner = self.unpack_dyn_trait(dest)?.1;
                trace!("dyn object layout: {:#?}", inner.layout);
                // recurse with the inner type
                return v.visit_field(self, Value::from_mem_place(inner), 0);
            },
            _ => {},
        };

        // If this is a scalar, visit it as such.
        // Things can be aggregates and have scalar layout at the same time, and that
        // is very relevant for `NonNull` and similar structs: We need to visit them
        // at their scalar layout *before* descending into their fields.
        // FIXME: We could avoid some redundant checks here. For newtypes wrapping
        // scalars, we do the same check on every "level" (e.g. first we check
        // MyNewtype and then the scalar in there).
        match v.layout().abi {
            layout::Abi::Uninhabited => {
                v.visit_uninhabited(self)?;
            }
            layout::Abi::Scalar(ref layout) => {
                v.visit_scalar(self, layout)?;
            }
            // FIXME: Should we do something for ScalarPair? Vector?
            _ => {}
        }

        // Check primitive types.  We do this after checking the scalar layout,
        // just to have that done as well.  Primitives can have varying layout,
        // so we check them separately and before aggregate handling.
        // It is CRITICAL that we get this check right, or we might be
        // validating the wrong thing!
        let primitive = match v.layout().fields {
            // Primitives appear as Union with 0 fields -- except for Boxes and fat pointers.
            layout::FieldPlacement::Union(0) => true,
            _ => v.layout().ty.builtin_deref(true).is_some(),
        };
        if primitive {
            return v.visit_primitive(self);
        }

        // Proceed into the fields.
        match v.layout().fields {
            layout::FieldPlacement::Union(fields) => {
                // Empty unions are not accepted by rustc. That's great, it means we can
                // use that as an unambiguous signal for detecting primitives.  Make sure
                // we did not miss any primitive.
                debug_assert!(fields > 0);
                // We can't traverse unions, their bits are allowed to be anything.
                // The fields don't need to correspond to any bit pattern of the union's fields.
                // See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
            },
            layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
                for i in 0..offsets.len() {
                    let val = v.value().project_field(self, i as u64)?;
                    v.visit_field(self, val, i)?;
                }
            },
            layout::FieldPlacement::Array { .. } => {
                if !v.handle_array(self)? {
                    // We still have to work!
                    // Let's get an mplace first.
                    let mplace = if v.layout().is_zst() {
                        // it's a ZST, the memory content cannot matter
                        MPlaceTy::dangling(v.layout(), self)
                    } else {
                        // non-ZST array/slice/str cannot be immediate
                        v.value().force_allocation(self)?
                    };
                    // Now iterate over it.
                    for (i, field) in self.mplace_array_fields(mplace)?.enumerate() {
                        v.visit_field(self, Value::from_mem_place(field?), i)?;
                    }
                }
            }
        }
        Ok(())
    }
}
<commit_msg>converting a VisitorValue to a MemPlace must not mutate anything<commit_after>//! Visitor for a run-time value with a given layout: Traverse enums, structs and other compound
//! types until we arrive at the leaves, with custom handling for primitive types.

use std::fmt;

use rustc::ty::layout::{self, TyLayout};
use rustc::ty;
use rustc::mir::interpret::{
    EvalResult,
};

use super::{
    Machine, EvalContext, MPlaceTy, PlaceTy, OpTy,
};

// A thing that we can project into, and that has a layout.
// This wouldn't have to depend on `Machine` but with the current type inference,
// that's just more convenient to work with (avoids repeading all the `Machine` bounds).
pub trait Value<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: Copy
{
    // Get this value's layout.
    fn layout(&self) -> TyLayout<'tcx>;

    // Make this a `MPlaceTy`, or panic if that's not possible.
    fn to_mem_place(
        self,
        ectx: &EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>>;

    // Create this from an `MPlaceTy`.
    fn from_mem_place(MPlaceTy<'tcx, M::PointerTag>) -> Self;

    // Read the current enum discriminant, and downcast to that.  Also return the
    // variant index.
    fn project_downcast(
        self,
        ectx: &EvalContext<'a, 'mir, 'tcx, M>
    ) -> EvalResult<'tcx, (Self, usize)>;

    // Project to the n-th field.
    fn project_field(
        self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self>;
}

// Operands and places are both values
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
    for OpTy<'tcx, M::PointerTag>
{
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.layout
    }

    #[inline(always)]
    fn to_mem_place(
        self,
        _ectx: &EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
        Ok(self.to_mem_place())
    }

    #[inline(always)]
    fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
        mplace.into()
    }

    #[inline(always)]
    fn project_downcast(
        self,
        ectx: &EvalContext<'a, 'mir, 'tcx, M>
    ) -> EvalResult<'tcx, (Self, usize)> {
        let idx = ectx.read_discriminant(self)?.1;
        Ok((ectx.operand_downcast(self, idx)?, idx))
    }

    #[inline(always)]
    fn project_field(
        self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self> {
        ectx.operand_field(self, field)
    }
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
    for MPlaceTy<'tcx, M::PointerTag>
{
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.layout
    }

    #[inline(always)]
    fn to_mem_place(
        self,
        _ectx: &EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
        Ok(self)
    }

    #[inline(always)]
    fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
        mplace
    }

    #[inline(always)]
    fn project_downcast(
        self,
        ectx: &EvalContext<'a, 'mir, 'tcx, M>
    ) -> EvalResult<'tcx, (Self, usize)> {
        let idx = ectx.read_discriminant(self.into())?.1;
        Ok((ectx.mplace_downcast(self, idx)?, idx))
    }

    #[inline(always)]
    fn project_field(
        self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self> {
        ectx.mplace_field(self, field)
    }
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Value<'a, 'mir, 'tcx, M>
    for PlaceTy<'tcx, M::PointerTag>
{
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.layout
    }

    #[inline(always)]
    fn to_mem_place(
        self,
        ectx: &EvalContext<'a, 'mir, 'tcx, M>,
    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
        // If this refers to a local, assert that it already has an allocation.
        Ok(ectx.place_to_op(self)?.to_mem_place())
    }

    #[inline(always)]
    fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self {
        mplace.into()
    }

    #[inline(always)]
    fn project_downcast(
        self,
        ectx: &EvalContext<'a, 'mir, 'tcx, M>
    ) -> EvalResult<'tcx, (Self, usize)> {
        let idx = ectx.read_discriminant(ectx.place_to_op(self)?)?.1;
        Ok((ectx.place_downcast(self, idx)?, idx))
    }

    #[inline(always)]
    fn project_field(
        self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
        field: u64,
    ) -> EvalResult<'tcx, Self> {
        ectx.place_field(self, field)
    }
}

// How to traverse a value and what to do when we are at the leaves.
pub trait ValueVisitor<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: fmt::Debug + Sized {
    type V: Value<'a, 'mir, 'tcx, M>;

    // There's a value in here.
    fn value(&self) -> &Self::V;

    // The value's layout (not meant to be overwritten).
    #[inline(always)]
    fn layout(&self) -> TyLayout<'tcx> {
        self.value().layout()
    }

    // Replace the value by `val`, which must be the `field`th field of `self`, then call
    // `visit_value` and then un-do everything that might have happened to the visitor state.
    // The point of this is that some visitors keep a stack of fields that we projected below,
    // and this lets us avoid copying that stack; instead they will pop the stack after
    // executing `visit_value`.
    fn visit_field(
        &mut self,
        ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
        val: Self::V,
        field: usize,
    ) -> EvalResult<'tcx>;

    // A chance for the visitor to do special (different or more efficient) handling for some
    // array types.  Return `true` if the value was handled and we should return.
    #[inline]
    fn handle_array(&mut self, _ectx: &EvalContext<'a, 'mir, 'tcx, M>)
        -> EvalResult<'tcx, bool>
    {
        Ok(false)
    }

    // Execute visitor on the current value.  Used for recursing.
    #[inline]
    fn visit(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
        -> EvalResult<'tcx>
    {
        ectx.walk_value(self)
    }

    // Actions on the leaves.
    fn visit_uninhabited(&mut self, _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
        -> EvalResult<'tcx>
    { Ok(()) }
    fn visit_scalar(&mut self, _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>, _layout: &layout::Scalar)
        -> EvalResult<'tcx>
    { Ok(()) }
    fn visit_primitive(&mut self, _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
        -> EvalResult<'tcx>
    { Ok(()) }
}

impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
    pub fn walk_value<V: ValueVisitor<'a, 'mir, 'tcx, M>>(
        &mut self,
        v: &mut V,
    ) -> EvalResult<'tcx> {
        trace!("walk_value: {:?}", v);

        // If this is a multi-variant layout, we have find the right one and proceed with that.
        // (No benefit from making this recursion, but it is equivalent to that.)
        match v.layout().variants {
            layout::Variants::NicheFilling { .. } |
            layout::Variants::Tagged { .. } => {
                let (inner, idx) = v.value().project_downcast(self)?;
                trace!("variant layout: {:#?}", inner.layout());
                // recurse with the inner type
                return v.visit_field(self, inner, idx);
            }
            layout::Variants::Single { .. } => {}
        }

        // Even for single variants, we might be able to get a more refined type:
        // If it is a trait object, switch to the actual type that was used to create it.
        match v.layout().ty.sty {
            ty::Dynamic(..) => {
                // immediate trait objects are not a thing
                let dest = v.value().to_mem_place(self)?;
                let inner = self.unpack_dyn_trait(dest)?.1;
                trace!("dyn object layout: {:#?}", inner.layout);
                // recurse with the inner type
                return v.visit_field(self, Value::from_mem_place(inner), 0);
            },
            _ => {},
        };

        // If this is a scalar, visit it as such.
        // Things can be aggregates and have scalar layout at the same time, and that
        // is very relevant for `NonNull` and similar structs: We need to visit them
        // at their scalar layout *before* descending into their fields.
        // FIXME: We could avoid some redundant checks here. For newtypes wrapping
        // scalars, we do the same check on every "level" (e.g. first we check
        // MyNewtype and then the scalar in there).
        match v.layout().abi {
            layout::Abi::Uninhabited => {
                v.visit_uninhabited(self)?;
            }
            layout::Abi::Scalar(ref layout) => {
                v.visit_scalar(self, layout)?;
            }
            // FIXME: Should we do something for ScalarPair? Vector?
            _ => {}
        }

        // Check primitive types.  We do this after checking the scalar layout,
        // just to have that done as well.  Primitives can have varying layout,
        // so we check them separately and before aggregate handling.
        // It is CRITICAL that we get this check right, or we might be
        // validating the wrong thing!
        let primitive = match v.layout().fields {
            // Primitives appear as Union with 0 fields -- except for Boxes and fat pointers.
            layout::FieldPlacement::Union(0) => true,
            _ => v.layout().ty.builtin_deref(true).is_some(),
        };
        if primitive {
            return v.visit_primitive(self);
        }

        // Proceed into the fields.
        match v.layout().fields {
            layout::FieldPlacement::Union(fields) => {
                // Empty unions are not accepted by rustc. That's great, it means we can
                // use that as an unambiguous signal for detecting primitives.  Make sure
                // we did not miss any primitive.
                debug_assert!(fields > 0);
                // We can't traverse unions, their bits are allowed to be anything.
                // The fields don't need to correspond to any bit pattern of the union's fields.
                // See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
            },
            layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
                for i in 0..offsets.len() {
                    let val = v.value().project_field(self, i as u64)?;
                    v.visit_field(self, val, i)?;
                }
            },
            layout::FieldPlacement::Array { .. } => {
                if !v.handle_array(self)? {
                    // We still have to work!
                    // Let's get an mplace first.
                    let mplace = if v.layout().is_zst() {
                        // it's a ZST, the memory content cannot matter
                        MPlaceTy::dangling(v.layout(), self)
                    } else {
                        // non-ZST array/slice/str cannot be immediate
                        v.value().to_mem_place(self)?
                    };
                    // Now iterate over it.
                    for (i, field) in self.mplace_array_fields(mplace)?.enumerate() {
                        v.visit_field(self, Value::from_mem_place(field?), i)?;
                    }
                }
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Std
use std::{
    ffi::{OsStr, OsString},
    iter::{Cloned, Flatten},
    slice::Iter,
};

use crate::INTERNAL_ERROR_MSG;

// TODO: Maybe make this public?
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ValueType {
    Unknown,
    #[cfg(feature = "env")]
    EnvVariable,
    CommandLine,
    DefaultValue,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct MatchedArg {
    pub(crate) occurs: u64,
    pub(crate) ty: ValueType,
    indices: Vec<usize>,
    vals: Vec<Vec<OsString>>,
    case_insensitive: bool,
}

impl Default for MatchedArg {
    fn default() -> Self {
        Self::new()
    }
}

impl MatchedArg {
    pub(crate) fn new() -> Self {
        MatchedArg {
            occurs: 0,
            ty: ValueType::Unknown,
            indices: Vec::new(),
            vals: Vec::new(),
            case_insensitive: false,
        }
    }

    pub(crate) fn indices(&self) -> Cloned<Iter<'_, usize>> {
        self.indices.iter().cloned()
    }

    pub(crate) fn get_index(&self, index: usize) -> Option<usize> {
        self.indices.get(index).cloned()
    }

    pub(crate) fn push_index(&mut self, index: usize) {
        self.indices.push(index)
    }

    pub(crate) fn vals(&self) -> Iter<Vec<OsString>> {
        self.vals.iter()
    }

    pub(crate) fn vals_flatten(&self) -> Flatten<Iter<Vec<OsString>>> {
        self.vals.iter().flatten()
    }

    pub(crate) fn first(&self) -> Option<&OsString> {
        self.vals_flatten().next()
    }

    pub(crate) fn push_val(&mut self, val: OsString) {
        self.vals.push(vec![val])
    }

    pub(crate) fn new_val_group(&mut self) {
        self.vals.push(vec![])
    }

    pub(crate) fn append_val(&mut self, val: OsString) {
        // We assume there is always a group created before.
        self.vals.last_mut().expect(INTERNAL_ERROR_MSG).push(val)
    }

    pub(crate) fn num_vals(&self) -> usize {
        self.vals.iter().flatten().count()
    }

    // Will be used later
    #[allow(dead_code)]
    pub(crate) fn num_vals_last_group(&self) -> usize {
        self.vals.last().map(|x| x.len()).unwrap_or(0)
    }

    pub(crate) fn is_vals_empty(&self) -> bool {
        self.vals.iter().flatten().count() == 0
    }

    // Will be used later
    #[allow(dead_code)]
    pub(crate) fn remove_vals(&mut self, len: usize) {
        let mut want_remove = len;
        let mut remove_group = None;
        let mut remove_val = None;
        for (i, g) in self.vals().enumerate() {
            if g.len() <= want_remove {
                want_remove -= g.len();
                remove_group = Some(i);
            } else {
                remove_val = Some(want_remove);
                break;
            }
        }
        if let Some(remove_group) = remove_group {
            self.vals.drain(0..=remove_group);
        }
        if let Some(remove_val) = remove_val {
            self.vals[0].drain(0..remove_val);
        }
    }

    pub(crate) fn override_vals(&mut self) {
        let len = self.vals.len();
        if len > 1 {
            self.vals.drain(0..len - 1);
        }
    }

    pub(crate) fn contains_val(&self, val: &str) -> bool {
        self.vals_flatten().any(|v| {
            if self.case_insensitive {
                v.eq_ignore_ascii_case(val)
            } else {
                OsString::as_os_str(v) == OsStr::new(val)
            }
        })
    }

    pub(crate) fn set_ty(&mut self, ty: ValueType) {
        self.ty = ty;
    }

    pub(crate) fn set_case_insensitive(&mut self, ci: bool) {
        self.case_insensitive = ci;
    }
}

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

    #[test]
    fn test_vals_override() {
        let mut m = MatchedArg::new();
        m.push_val("aaa".into());
        m.new_val_group();
        m.append_val("bbb".into());
        m.append_val("ccc".into());
        m.new_val_group();
        m.append_val("ddd".into());
        m.push_val("eee".into());
        m.new_val_group();
        m.append_val("fff".into());
        m.append_val("ggg".into());
        m.append_val("hhh".into());
        m.append_val("iii".into());

        m.override_vals();
        let vals: Vec<&Vec<OsString>> = m.vals().collect();
        assert_eq!(
            vals,
            vec![&vec![
                OsString::from("fff"),
                OsString::from("ggg"),
                OsString::from("hhh"),
                OsString::from("iii"),
            ]]
        );
        m.override_vals();

        let vals: Vec<&Vec<OsString>> = m.vals().collect();
        assert_eq!(
            vals,
            vec![&vec![
                OsString::from("fff"),
                OsString::from("ggg"),
                OsString::from("hhh"),
                OsString::from("iii"),
            ]]
        );
    }

    #[test]
    fn test_grouped_vals_first() {
        let mut m = MatchedArg::new();
        m.new_val_group();
        m.new_val_group();
        m.append_val("bbb".into());
        m.append_val("ccc".into());
        assert_eq!(m.first(), Some(&OsString::from("bbb")));
    }

    #[test]
    fn test_grouped_vals_push_and_append() {
        let mut m = MatchedArg::new();
        m.push_val("aaa".into());
        m.new_val_group();
        m.append_val("bbb".into());
        m.append_val("ccc".into());
        m.new_val_group();
        m.append_val("ddd".into());
        m.push_val("eee".into());
        m.new_val_group();
        m.append_val("fff".into());
        m.append_val("ggg".into());
        m.append_val("hhh".into());
        m.append_val("iii".into());

        let vals: Vec<&Vec<OsString>> = m.vals().collect();
        assert_eq!(
            vals,
            vec![
                &vec![OsString::from("aaa")],
                &vec![OsString::from("bbb"), OsString::from("ccc"),],
                &vec![OsString::from("ddd")],
                &vec![OsString::from("eee")],
                &vec![
                    OsString::from("fff"),
                    OsString::from("ggg"),
                    OsString::from("hhh"),
                    OsString::from("iii"),
                ]
            ]
        )
    }

    #[test]
    fn test_grouped_vals_removal() {
        let m = {
            let mut m = MatchedArg::new();
            m.push_val("aaa".into());
            m.new_val_group();
            m.append_val("bbb".into());
            m.append_val("ccc".into());
            m.new_val_group();
            m.append_val("ddd".into());
            m.push_val("eee".into());
            m.new_val_group();
            m.append_val("fff".into());
            m.append_val("ggg".into());
            m.append_val("hhh".into());
            m.append_val("iii".into());
            m
        };
        {
            let mut m = m.clone();
            m.remove_vals(0);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![
                    &vec![OsString::from("aaa")],
                    &vec![OsString::from("bbb"), OsString::from("ccc"),],
                    &vec![OsString::from("ddd")],
                    &vec![OsString::from("eee")],
                    &vec![
                        OsString::from("fff"),
                        OsString::from("ggg"),
                        OsString::from("hhh"),
                        OsString::from("iii"),
                    ]
                ]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(1);
            let vals0 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals0,
                vec![
                    &vec![OsString::from("bbb"), OsString::from("ccc"),],
                    &vec![OsString::from("ddd")],
                    &vec![OsString::from("eee")],
                    &vec![
                        OsString::from("fff"),
                        OsString::from("ggg"),
                        OsString::from("hhh"),
                        OsString::from("iii"),
                    ]
                ]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(2);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![
                    &vec![OsString::from("ccc"),],
                    &vec![OsString::from("ddd")],
                    &vec![OsString::from("eee")],
                    &vec![
                        OsString::from("fff"),
                        OsString::from("ggg"),
                        OsString::from("hhh"),
                        OsString::from("iii"),
                    ]
                ]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(3);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![
                    &vec![OsString::from("ddd")],
                    &vec![OsString::from("eee")],
                    &vec![
                        OsString::from("fff"),
                        OsString::from("ggg"),
                        OsString::from("hhh"),
                        OsString::from("iii"),
                    ]
                ]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(4);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![
                    &vec![OsString::from("eee")],
                    &vec![
                        OsString::from("fff"),
                        OsString::from("ggg"),
                        OsString::from("hhh"),
                        OsString::from("iii"),
                    ]
                ]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(5);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![&vec![
                    OsString::from("fff"),
                    OsString::from("ggg"),
                    OsString::from("hhh"),
                    OsString::from("iii"),
                ]]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(7);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![&vec![OsString::from("hhh"), OsString::from("iii"),]]
            );
        }

        {
            let mut m = m;
            m.remove_vals(9);
            assert_eq!(m.vals().next(), None);
        }
    }
}
<commit_msg>fix: Allow unicode aware case insensitivity<commit_after>// Std
use std::{
    ffi::{OsStr, OsString},
    iter::{Cloned, Flatten},
    slice::Iter,
};

use crate::util::eq_ignore_case;
use crate::INTERNAL_ERROR_MSG;

// TODO: Maybe make this public?
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ValueType {
    Unknown,
    #[cfg(feature = "env")]
    EnvVariable,
    CommandLine,
    DefaultValue,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct MatchedArg {
    pub(crate) occurs: u64,
    pub(crate) ty: ValueType,
    indices: Vec<usize>,
    vals: Vec<Vec<OsString>>,
    case_insensitive: bool,
}

impl Default for MatchedArg {
    fn default() -> Self {
        Self::new()
    }
}

impl MatchedArg {
    pub(crate) fn new() -> Self {
        MatchedArg {
            occurs: 0,
            ty: ValueType::Unknown,
            indices: Vec::new(),
            vals: Vec::new(),
            case_insensitive: false,
        }
    }

    pub(crate) fn indices(&self) -> Cloned<Iter<'_, usize>> {
        self.indices.iter().cloned()
    }

    pub(crate) fn get_index(&self, index: usize) -> Option<usize> {
        self.indices.get(index).cloned()
    }

    pub(crate) fn push_index(&mut self, index: usize) {
        self.indices.push(index)
    }

    pub(crate) fn vals(&self) -> Iter<Vec<OsString>> {
        self.vals.iter()
    }

    pub(crate) fn vals_flatten(&self) -> Flatten<Iter<Vec<OsString>>> {
        self.vals.iter().flatten()
    }

    pub(crate) fn first(&self) -> Option<&OsString> {
        self.vals_flatten().next()
    }

    pub(crate) fn push_val(&mut self, val: OsString) {
        self.vals.push(vec![val])
    }

    pub(crate) fn new_val_group(&mut self) {
        self.vals.push(vec![])
    }

    pub(crate) fn append_val(&mut self, val: OsString) {
        // We assume there is always a group created before.
        self.vals.last_mut().expect(INTERNAL_ERROR_MSG).push(val)
    }

    pub(crate) fn num_vals(&self) -> usize {
        self.vals.iter().flatten().count()
    }

    // Will be used later
    #[allow(dead_code)]
    pub(crate) fn num_vals_last_group(&self) -> usize {
        self.vals.last().map(|x| x.len()).unwrap_or(0)
    }

    pub(crate) fn is_vals_empty(&self) -> bool {
        self.vals.iter().flatten().count() == 0
    }

    // Will be used later
    #[allow(dead_code)]
    pub(crate) fn remove_vals(&mut self, len: usize) {
        let mut want_remove = len;
        let mut remove_group = None;
        let mut remove_val = None;
        for (i, g) in self.vals().enumerate() {
            if g.len() <= want_remove {
                want_remove -= g.len();
                remove_group = Some(i);
            } else {
                remove_val = Some(want_remove);
                break;
            }
        }
        if let Some(remove_group) = remove_group {
            self.vals.drain(0..=remove_group);
        }
        if let Some(remove_val) = remove_val {
            self.vals[0].drain(0..remove_val);
        }
    }

    pub(crate) fn override_vals(&mut self) {
        let len = self.vals.len();
        if len > 1 {
            self.vals.drain(0..len - 1);
        }
    }

    pub(crate) fn contains_val(&self, val: &str) -> bool {
        self.vals_flatten().any(|v| {
            if self.case_insensitive {
                // If `v` isn't utf8, it can't match `val`, so `OsStr::to_str` should be fine
                v.to_str().map_or(false, |v| eq_ignore_case(v, val))
            } else {
                OsString::as_os_str(v) == OsStr::new(val)
            }
        })
    }

    pub(crate) fn set_ty(&mut self, ty: ValueType) {
        self.ty = ty;
    }

    pub(crate) fn set_case_insensitive(&mut self, ci: bool) {
        self.case_insensitive = ci;
    }
}

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

    #[test]
    fn test_vals_override() {
        let mut m = MatchedArg::new();
        m.push_val("aaa".into());
        m.new_val_group();
        m.append_val("bbb".into());
        m.append_val("ccc".into());
        m.new_val_group();
        m.append_val("ddd".into());
        m.push_val("eee".into());
        m.new_val_group();
        m.append_val("fff".into());
        m.append_val("ggg".into());
        m.append_val("hhh".into());
        m.append_val("iii".into());

        m.override_vals();
        let vals: Vec<&Vec<OsString>> = m.vals().collect();
        assert_eq!(
            vals,
            vec![&vec![
                OsString::from("fff"),
                OsString::from("ggg"),
                OsString::from("hhh"),
                OsString::from("iii"),
            ]]
        );
        m.override_vals();

        let vals: Vec<&Vec<OsString>> = m.vals().collect();
        assert_eq!(
            vals,
            vec![&vec![
                OsString::from("fff"),
                OsString::from("ggg"),
                OsString::from("hhh"),
                OsString::from("iii"),
            ]]
        );
    }

    #[test]
    fn test_grouped_vals_first() {
        let mut m = MatchedArg::new();
        m.new_val_group();
        m.new_val_group();
        m.append_val("bbb".into());
        m.append_val("ccc".into());
        assert_eq!(m.first(), Some(&OsString::from("bbb")));
    }

    #[test]
    fn test_grouped_vals_push_and_append() {
        let mut m = MatchedArg::new();
        m.push_val("aaa".into());
        m.new_val_group();
        m.append_val("bbb".into());
        m.append_val("ccc".into());
        m.new_val_group();
        m.append_val("ddd".into());
        m.push_val("eee".into());
        m.new_val_group();
        m.append_val("fff".into());
        m.append_val("ggg".into());
        m.append_val("hhh".into());
        m.append_val("iii".into());

        let vals: Vec<&Vec<OsString>> = m.vals().collect();
        assert_eq!(
            vals,
            vec![
                &vec![OsString::from("aaa")],
                &vec![OsString::from("bbb"), OsString::from("ccc"),],
                &vec![OsString::from("ddd")],
                &vec![OsString::from("eee")],
                &vec![
                    OsString::from("fff"),
                    OsString::from("ggg"),
                    OsString::from("hhh"),
                    OsString::from("iii"),
                ]
            ]
        )
    }

    #[test]
    fn test_grouped_vals_removal() {
        let m = {
            let mut m = MatchedArg::new();
            m.push_val("aaa".into());
            m.new_val_group();
            m.append_val("bbb".into());
            m.append_val("ccc".into());
            m.new_val_group();
            m.append_val("ddd".into());
            m.push_val("eee".into());
            m.new_val_group();
            m.append_val("fff".into());
            m.append_val("ggg".into());
            m.append_val("hhh".into());
            m.append_val("iii".into());
            m
        };
        {
            let mut m = m.clone();
            m.remove_vals(0);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![
                    &vec![OsString::from("aaa")],
                    &vec![OsString::from("bbb"), OsString::from("ccc"),],
                    &vec![OsString::from("ddd")],
                    &vec![OsString::from("eee")],
                    &vec![
                        OsString::from("fff"),
                        OsString::from("ggg"),
                        OsString::from("hhh"),
                        OsString::from("iii"),
                    ]
                ]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(1);
            let vals0 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals0,
                vec![
                    &vec![OsString::from("bbb"), OsString::from("ccc"),],
                    &vec![OsString::from("ddd")],
                    &vec![OsString::from("eee")],
                    &vec![
                        OsString::from("fff"),
                        OsString::from("ggg"),
                        OsString::from("hhh"),
                        OsString::from("iii"),
                    ]
                ]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(2);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![
                    &vec![OsString::from("ccc"),],
                    &vec![OsString::from("ddd")],
                    &vec![OsString::from("eee")],
                    &vec![
                        OsString::from("fff"),
                        OsString::from("ggg"),
                        OsString::from("hhh"),
                        OsString::from("iii"),
                    ]
                ]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(3);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![
                    &vec![OsString::from("ddd")],
                    &vec![OsString::from("eee")],
                    &vec![
                        OsString::from("fff"),
                        OsString::from("ggg"),
                        OsString::from("hhh"),
                        OsString::from("iii"),
                    ]
                ]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(4);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![
                    &vec![OsString::from("eee")],
                    &vec![
                        OsString::from("fff"),
                        OsString::from("ggg"),
                        OsString::from("hhh"),
                        OsString::from("iii"),
                    ]
                ]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(5);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![&vec![
                    OsString::from("fff"),
                    OsString::from("ggg"),
                    OsString::from("hhh"),
                    OsString::from("iii"),
                ]]
            );
        }

        {
            let mut m = m.clone();
            m.remove_vals(7);
            let vals1 = m.vals().collect::<Vec<_>>();
            assert_eq!(
                vals1,
                vec![&vec![OsString::from("hhh"), OsString::from("iii"),]]
            );
        }

        {
            let mut m = m;
            m.remove_vals(9);
            assert_eq!(m.vals().next(), None);
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains data structures for representing syntax definitions.
//! Everything is public because I want this library to be useful in super
//! integrated cases like text editors and I have no idea what kind of monkeying
//! you might want to do with the data. Perhaps parsing your own syntax format
//! into this data structure?
use std::collections::HashMap;
use onig::{self, Regex, Region, Syntax};
use std::rc::{Rc, Weak};
use std::cell::RefCell;
use super::scope::*;
use regex_syntax::quote;
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};

pub type CaptureMapping = HashMap<usize, Vec<Scope>>;
pub type ContextPtr = Rc<RefCell<Context>>;

/// The main data structure representing a syntax definition loaded from a
/// `.sublime-syntax` file. You'll probably only need these as references
/// to be passed around to parsing code.
///
/// Some useful public fields are the `name` field which is a human readable
/// name to display in syntax lists, and the `hidden` field which means hide
/// this syntax from any lists because it is for internal use.
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SyntaxDefinition {
    pub name: String,
    pub file_extensions: Vec<String>,
    pub scope: Scope,
    pub first_line_match: Option<String>,
    pub hidden: bool,
    /// Filled in at link time to avoid serializing it multiple times
    pub prototype: Option<ContextPtr>,

    pub variables: HashMap<String, String>,
    pub contexts: HashMap<String, ContextPtr>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Context {
    pub meta_scope: Vec<Scope>,
    pub meta_content_scope: Vec<Scope>,
    /// This being set false in the syntax file implies this field being set false,
    /// but it can also be set falso for contexts that don't include the prototype for other reasons
    pub meta_include_prototype: bool,
    /// This is filled in by the linker at link time
    /// for contexts that have `meta_include_prototype==true`
    /// and are not included from the prototype.
    pub prototype: Option<ContextPtr>,
    pub uses_backrefs: bool,

    pub patterns: Vec<Pattern>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub enum Pattern {
    Match(MatchPattern),
    Include(ContextReference),
}

/// Used to iterate over all the match patterns in a context.
/// Basically walks the tree of patterns and include directives
/// in the correct order.
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MatchIter {
    ctx_stack: Vec<ContextPtr>,
    index_stack: Vec<usize>,
}

#[derive(Debug)]
pub struct MatchPattern {
    pub has_captures: bool,
    pub regex_str: String,
    pub regex: Option<Regex>,
    pub scope: Vec<Scope>,
    pub captures: Option<CaptureMapping>,
    pub operation: MatchOperation,
    pub with_prototype: Option<ContextPtr>,
}

/// This wrapper only exists so that I can implement a serialization
/// trait that crashes if you try and serialize this.
#[derive(Debug)]
pub struct LinkerLink {
    pub link: Weak<RefCell<Context>>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub enum ContextReference {
    Named(String),
    ByScope {
        scope: Scope,
        sub_context: Option<String>,
    },
    File {
        name: String,
        sub_context: Option<String>,
    },
    Inline(ContextPtr),
    Direct(LinkerLink),
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub enum MatchOperation {
    Push(Vec<ContextReference>),
    Set(Vec<ContextReference>),
    Pop,
    None,
}

impl Iterator for MatchIter {
    type Item = (ContextPtr, usize);

    fn next(&mut self) -> Option<(ContextPtr, usize)> {
        loop {
            if self.ctx_stack.is_empty() {
                return None;
            }
            // uncomment for debugging infinite recursion
            // println!("{:?}", self.index_stack);
            // use std::thread::sleep_ms;
            // sleep_ms(500);
            let last_index = self.ctx_stack.len() - 1;
            let context_ref = self.ctx_stack[last_index].clone();
            let context = context_ref.borrow();
            let index = self.index_stack[last_index];
            self.index_stack[last_index] = index + 1;
            if index < context.patterns.len() {
                match context.patterns[index] {
                    Pattern::Match(_) => return Some((context_ref.clone(), index)),
                    Pattern::Include(ref ctx_ref) => {
                        let ctx_ptr = match ctx_ref {
                            &ContextReference::Inline(ref ctx_ptr) => ctx_ptr.clone(),
                            &ContextReference::Direct(ref ctx_ptr) => {
                                ctx_ptr.link.upgrade().unwrap()
                            }
                            _ => panic!("Can only iterate patterns after linking: {:?}", ctx_ref),
                        };
                        self.ctx_stack.push(ctx_ptr);
                        self.index_stack.push(0);
                    }
                }
            } else {
                self.ctx_stack.pop();
                self.index_stack.pop();
            }
        }
    }
}

/// Returns an iterator over all the match patterns in this context.
/// It recursively follows include directives. Can only be run on
/// contexts that have already been linked up.
pub fn context_iter(ctx: ContextPtr) -> MatchIter {
    MatchIter {
        ctx_stack: vec![ctx],
        index_stack: vec![0],
    }
}

impl Context {
    /// Returns the match pattern at an index, panics if the thing isn't a match pattern
    pub fn match_at(&self, index: usize) -> &MatchPattern {
        match self.patterns[index] {
            Pattern::Match(ref match_pat) => match_pat,
            _ => panic!("bad index to match_at"),
        }
    }

    /// Returns a mutable reference, otherwise like `match_at`
    pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern {
        match self.patterns[index] {
            Pattern::Match(ref mut match_pat) => match_pat,
            _ => panic!("bad index to match_at"),
        }
    }
}

impl ContextReference {
    /// find the pointed to context, panics if ref is not linked
    pub fn resolve(&self) -> ContextPtr {
        match self {
            &ContextReference::Inline(ref ptr) => ptr.clone(),
            &ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(),
            _ => panic!("Can only call resolve on linked references: {:?}", self),
        }
    }
}

impl MatchPattern {
    /// substitutes back-refs in Regex with regions from s
    /// used for match patterns which refer to captures from the pattern
    /// that pushed them.
    pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String {
        let mut reg_str = String::new();

        let mut last_was_escape = false;
        for c in self.regex_str.chars() {
            if last_was_escape && c.is_digit(10) {
                let val = c.to_digit(10).unwrap();
                if let Some((start, end)) = region.pos(val as usize) {
                    let escaped = quote(&s[start..end]);
                    reg_str.push_str(&escaped);
                }
            } else if last_was_escape {
                reg_str.push('\\');
                reg_str.push(c);
            } else if c != '\\' {
                reg_str.push(c);
            }

            last_was_escape = c == '\\' && !last_was_escape;
        }
        reg_str
    }

    /// Used by the parser to compile a regex which needs to reference
    /// regions from another matched pattern.
    pub fn compile_with_refs(&self, region: &Region, s: &str) -> Regex {
        // TODO don't panic on invalid regex
        Regex::with_options(&self.regex_with_substitutes(region, s),
                            onig::REGEX_OPTION_CAPTURE_GROUP,
                            Syntax::default())
            .unwrap()
    }

    fn compile_regex(&mut self) {
        // TODO don't panic on invalid regex
        let compiled = Regex::with_options(&self.regex_str,
                                           onig::REGEX_OPTION_CAPTURE_GROUP,
                                           Syntax::default())
            .unwrap();
        self.regex = Some(compiled);
    }

    /// Makes sure the regex is compiled if it doesn't have captures.
    /// May compile the regex if it isn't, panicing if compilation fails.
    #[inline]
    pub fn ensure_compiled_if_possible(&mut self) {
        if self.regex.is_none() && !self.has_captures {
            self.compile_regex();
        }
    }
}

/// Only valid to use this on a syntax which hasn't been linked up to other syntaxes yet
impl Encodable for MatchPattern {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("MatchPattern", 6, |s| {
            try!(s.emit_struct_field("has_captures", 0, |s| self.has_captures.encode(s)));
            try!(s.emit_struct_field("regex_str", 1, |s| self.regex_str.encode(s)));
            try!(s.emit_struct_field("scope", 2, |s| self.scope.encode(s)));
            try!(s.emit_struct_field("captures", 3, |s| self.captures.encode(s)));
            try!(s.emit_struct_field("operation", 4, |s| self.operation.encode(s)));
            try!(s.emit_struct_field("with_prototype", 5, |s| self.with_prototype.encode(s)));
            Ok(())
        })
    }
}

/// Syntaxes decoded by this won't have compiled regexes
impl Decodable for MatchPattern {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        d.read_struct("MatchPattern", 6, |d| {
            let match_pat = MatchPattern {
                has_captures: try!(d.read_struct_field("has_captures", 0, Decodable::decode)),
                regex: None,
                regex_str: try!(d.read_struct_field("regex_str", 1, Decodable::decode)),
                scope: try!(d.read_struct_field("scope", 2, Decodable::decode)),
                captures: try!(d.read_struct_field("captures", 3, Decodable::decode)),
                operation: try!(d.read_struct_field("operation", 4, Decodable::decode)),
                with_prototype: try!(d.read_struct_field("with_prototype", 5, Decodable::decode)),
            };

            Ok(match_pat)
        })
    }
}

/// Just panics, we can't do anything with linked up syntaxes
impl Encodable for LinkerLink {
    fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
        panic!("Can't encode syntax definitions which have been linked")
    }
}

/// Just panics, we can't do anything with linked up syntaxes
impl Decodable for LinkerLink {
    fn decode<D: Decoder>(_: &mut D) -> Result<LinkerLink, D::Error> {
        panic!("No linked syntax should ever have gotten encoded")
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn can_compile_refs() {
        use onig::{self, Regex, Region};
        let pat = MatchPattern {
            has_captures: true,
            regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"),
            regex: None,
            scope: vec![],
            captures: None,
            operation: MatchOperation::None,
            with_prototype: None,
        };
        let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap();
        let mut region = Region::new();
        let s = r"\[]()bcde";
        assert!(r.match_with_options(s, 0, onig::SEARCH_OPTION_NONE, Some(&mut region)).is_some());

        let regex_res = pat.regex_with_substitutes(&region, s);
        assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz");
        pat.compile_with_refs(&region, s);
    }
}
<commit_msg>clone syntax-definitions too<commit_after>//! This module contains data structures for representing syntax definitions.
//! Everything is public because I want this library to be useful in super
//! integrated cases like text editors and I have no idea what kind of monkeying
//! you might want to do with the data. Perhaps parsing your own syntax format
//! into this data structure?
use std::collections::HashMap;
use onig::{self, Regex, Region, Syntax};
use std::rc::{Rc, Weak};
use std::cell::RefCell;
use super::scope::*;
use regex_syntax::quote;
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};

pub type CaptureMapping = HashMap<usize, Vec<Scope>>;
pub type ContextPtr = Rc<RefCell<Context>>;

/// The main data structure representing a syntax definition loaded from a
/// `.sublime-syntax` file. You'll probably only need these as references
/// to be passed around to parsing code.
///
/// Some useful public fields are the `name` field which is a human readable
/// name to display in syntax lists, and the `hidden` field which means hide
/// this syntax from any lists because it is for internal use.
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct SyntaxDefinition {
    pub name: String,
    pub file_extensions: Vec<String>,
    pub scope: Scope,
    pub first_line_match: Option<String>,
    pub hidden: bool,
    /// Filled in at link time to avoid serializing it multiple times
    pub prototype: Option<ContextPtr>,

    pub variables: HashMap<String, String>,
    pub contexts: HashMap<String, ContextPtr>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Context {
    pub meta_scope: Vec<Scope>,
    pub meta_content_scope: Vec<Scope>,
    /// This being set false in the syntax file implies this field being set false,
    /// but it can also be set falso for contexts that don't include the prototype for other reasons
    pub meta_include_prototype: bool,
    /// This is filled in by the linker at link time
    /// for contexts that have `meta_include_prototype==true`
    /// and are not included from the prototype.
    pub prototype: Option<ContextPtr>,
    pub uses_backrefs: bool,

    pub patterns: Vec<Pattern>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub enum Pattern {
    Match(MatchPattern),
    Include(ContextReference),
}

/// Used to iterate over all the match patterns in a context.
/// Basically walks the tree of patterns and include directives
/// in the correct order.
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MatchIter {
    ctx_stack: Vec<ContextPtr>,
    index_stack: Vec<usize>,
}

#[derive(Debug)]
pub struct MatchPattern {
    pub has_captures: bool,
    pub regex_str: String,
    pub regex: Option<Regex>,
    pub scope: Vec<Scope>,
    pub captures: Option<CaptureMapping>,
    pub operation: MatchOperation,
    pub with_prototype: Option<ContextPtr>,
}

/// This wrapper only exists so that I can implement a serialization
/// trait that crashes if you try and serialize this.
#[derive(Debug)]
pub struct LinkerLink {
    pub link: Weak<RefCell<Context>>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub enum ContextReference {
    Named(String),
    ByScope {
        scope: Scope,
        sub_context: Option<String>,
    },
    File {
        name: String,
        sub_context: Option<String>,
    },
    Inline(ContextPtr),
    Direct(LinkerLink),
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub enum MatchOperation {
    Push(Vec<ContextReference>),
    Set(Vec<ContextReference>),
    Pop,
    None,
}

impl Iterator for MatchIter {
    type Item = (ContextPtr, usize);

    fn next(&mut self) -> Option<(ContextPtr, usize)> {
        loop {
            if self.ctx_stack.is_empty() {
                return None;
            }
            // uncomment for debugging infinite recursion
            // println!("{:?}", self.index_stack);
            // use std::thread::sleep_ms;
            // sleep_ms(500);
            let last_index = self.ctx_stack.len() - 1;
            let context_ref = self.ctx_stack[last_index].clone();
            let context = context_ref.borrow();
            let index = self.index_stack[last_index];
            self.index_stack[last_index] = index + 1;
            if index < context.patterns.len() {
                match context.patterns[index] {
                    Pattern::Match(_) => return Some((context_ref.clone(), index)),
                    Pattern::Include(ref ctx_ref) => {
                        let ctx_ptr = match ctx_ref {
                            &ContextReference::Inline(ref ctx_ptr) => ctx_ptr.clone(),
                            &ContextReference::Direct(ref ctx_ptr) => {
                                ctx_ptr.link.upgrade().unwrap()
                            }
                            _ => panic!("Can only iterate patterns after linking: {:?}", ctx_ref),
                        };
                        self.ctx_stack.push(ctx_ptr);
                        self.index_stack.push(0);
                    }
                }
            } else {
                self.ctx_stack.pop();
                self.index_stack.pop();
            }
        }
    }
}

/// Returns an iterator over all the match patterns in this context.
/// It recursively follows include directives. Can only be run on
/// contexts that have already been linked up.
pub fn context_iter(ctx: ContextPtr) -> MatchIter {
    MatchIter {
        ctx_stack: vec![ctx],
        index_stack: vec![0],
    }
}

impl Context {
    /// Returns the match pattern at an index, panics if the thing isn't a match pattern
    pub fn match_at(&self, index: usize) -> &MatchPattern {
        match self.patterns[index] {
            Pattern::Match(ref match_pat) => match_pat,
            _ => panic!("bad index to match_at"),
        }
    }

    /// Returns a mutable reference, otherwise like `match_at`
    pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern {
        match self.patterns[index] {
            Pattern::Match(ref mut match_pat) => match_pat,
            _ => panic!("bad index to match_at"),
        }
    }
}

impl ContextReference {
    /// find the pointed to context, panics if ref is not linked
    pub fn resolve(&self) -> ContextPtr {
        match self {
            &ContextReference::Inline(ref ptr) => ptr.clone(),
            &ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(),
            _ => panic!("Can only call resolve on linked references: {:?}", self),
        }
    }
}

impl MatchPattern {
    /// substitutes back-refs in Regex with regions from s
    /// used for match patterns which refer to captures from the pattern
    /// that pushed them.
    pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String {
        let mut reg_str = String::new();

        let mut last_was_escape = false;
        for c in self.regex_str.chars() {
            if last_was_escape && c.is_digit(10) {
                let val = c.to_digit(10).unwrap();
                if let Some((start, end)) = region.pos(val as usize) {
                    let escaped = quote(&s[start..end]);
                    reg_str.push_str(&escaped);
                }
            } else if last_was_escape {
                reg_str.push('\\');
                reg_str.push(c);
            } else if c != '\\' {
                reg_str.push(c);
            }

            last_was_escape = c == '\\' && !last_was_escape;
        }
        reg_str
    }

    /// Used by the parser to compile a regex which needs to reference
    /// regions from another matched pattern.
    pub fn compile_with_refs(&self, region: &Region, s: &str) -> Regex {
        // TODO don't panic on invalid regex
        Regex::with_options(&self.regex_with_substitutes(region, s),
                            onig::REGEX_OPTION_CAPTURE_GROUP,
                            Syntax::default())
            .unwrap()
    }

    fn compile_regex(&mut self) {
        // TODO don't panic on invalid regex
        let compiled = Regex::with_options(&self.regex_str,
                                           onig::REGEX_OPTION_CAPTURE_GROUP,
                                           Syntax::default())
            .unwrap();
        self.regex = Some(compiled);
    }

    /// Makes sure the regex is compiled if it doesn't have captures.
    /// May compile the regex if it isn't, panicing if compilation fails.
    #[inline]
    pub fn ensure_compiled_if_possible(&mut self) {
        if self.regex.is_none() && !self.has_captures {
            self.compile_regex();
        }
    }
}

/// Only valid to use this on a syntax which hasn't been linked up to other syntaxes yet
impl Encodable for MatchPattern {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("MatchPattern", 6, |s| {
            try!(s.emit_struct_field("has_captures", 0, |s| self.has_captures.encode(s)));
            try!(s.emit_struct_field("regex_str", 1, |s| self.regex_str.encode(s)));
            try!(s.emit_struct_field("scope", 2, |s| self.scope.encode(s)));
            try!(s.emit_struct_field("captures", 3, |s| self.captures.encode(s)));
            try!(s.emit_struct_field("operation", 4, |s| self.operation.encode(s)));
            try!(s.emit_struct_field("with_prototype", 5, |s| self.with_prototype.encode(s)));
            Ok(())
        })
    }
}

/// Syntaxes decoded by this won't have compiled regexes
impl Decodable for MatchPattern {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        d.read_struct("MatchPattern", 6, |d| {
            let match_pat = MatchPattern {
                has_captures: try!(d.read_struct_field("has_captures", 0, Decodable::decode)),
                regex: None,
                regex_str: try!(d.read_struct_field("regex_str", 1, Decodable::decode)),
                scope: try!(d.read_struct_field("scope", 2, Decodable::decode)),
                captures: try!(d.read_struct_field("captures", 3, Decodable::decode)),
                operation: try!(d.read_struct_field("operation", 4, Decodable::decode)),
                with_prototype: try!(d.read_struct_field("with_prototype", 5, Decodable::decode)),
            };

            Ok(match_pat)
        })
    }
}

/// Just panics, we can't do anything with linked up syntaxes
impl Encodable for LinkerLink {
    fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
        panic!("Can't encode syntax definitions which have been linked")
    }
}

/// Just panics, we can't do anything with linked up syntaxes
impl Decodable for LinkerLink {
    fn decode<D: Decoder>(_: &mut D) -> Result<LinkerLink, D::Error> {
        panic!("No linked syntax should ever have gotten encoded")
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn can_compile_refs() {
        use onig::{self, Regex, Region};
        let pat = MatchPattern {
            has_captures: true,
            regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"),
            regex: None,
            scope: vec![],
            captures: None,
            operation: MatchOperation::None,
            with_prototype: None,
        };
        let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap();
        let mut region = Region::new();
        let s = r"\[]()bcde";
        assert!(r.match_with_options(s, 0, onig::SEARCH_OPTION_NONE, Some(&mut region)).is_some());

        let regex_res = pat.regex_with_substitutes(&region, s);
        assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz");
        pat.compile_with_refs(&region, s);
    }
}
<|endoftext|>


<commit_before>mod binop;
mod unop;

use super::{LuaError, Result, var_to_string};
use super::types::{LuaValue, LuaTable, LuaState};

use nom_lua53;
use std;

// What do we say? We say "Merci Basile!"
fn lit_to_string(string: &nom_lua53::string::StringLit) -> String {
    return String::from_utf8_lossy(&(string.0)).to_string();
}

fn num_coercion(val: LuaValue) -> LuaValue {
    match val {
        LuaValue::Str(s) => {
            let parsed =  str::parse::<isize>(&s);
            match parsed {
                Ok(n) => LuaValue::Integer(n),
                Err(_) => {
                    let parsed =  str::parse::<f64>(&s);
                    match parsed {
                        Ok(n) => LuaValue::Float(n),
                        Err(_) => LuaValue::Str(s)
                    }
                }
            }
        },
        _ => val
    }
}

pub fn eval_expr(expr: &nom_lua53::Exp, ctx: &LuaState) -> Result<LuaValue> {
    match *expr {
        nom_lua53::Exp::Nil => Ok(LuaValue::Nil),
        nom_lua53::Exp::Bool(val) => Ok(LuaValue::Boolean(val)),
        nom_lua53::Exp::Num(val) => Ok(match val {
            nom_lua53::num::Numeral::Float(fl) => LuaValue::Float(fl),
            nom_lua53::num::Numeral::Int(i) => LuaValue::Integer(i),
        }),
        nom_lua53::Exp::BinExp(ref left, ref op, ref right) => binop::eval_binary_expr(left, right, &op, ctx),
        nom_lua53::Exp::UnExp(ref operator, ref operand) => unop::eval_unary_expr(operand, &operator, ctx),
        nom_lua53::Exp::Str(ref s) => Ok(LuaValue::Str(lit_to_string(s))),
        nom_lua53::Exp::Table(ref t) => eval_inline_table(t, ctx),
        nom_lua53::Exp::Ellipses => Err(LuaError::NotImplementedError),
        nom_lua53::Exp::FuncCall(_) => Err(LuaError::NotImplementedError),
        nom_lua53::Exp::Lambda(_) => Err(LuaError::NotImplementedError),
        nom_lua53::Exp::PrefixExp(_) => Err(LuaError::NotImplementedError),
    }
}

fn eval_inline_table(src: &nom_lua53::TableLit, ctx: &LuaState) ->  Result<LuaValue> {
    // First, we count how many positional epxressions there are to only do one allocation.
    let mut sequence_count = 0;
    for field in src.into_iter() {
        match field {
            &nom_lua53::Field::PosAssign(_) => sequence_count = sequence_count+1,
            _ => ()
        }
    }

    let ret = LuaTable::with_capacity(ctx.get_ref_id(), sequence_count);
    let mut next_index = 1;
    for field in src.iter() {
        match *field {
            nom_lua53::Field::PosAssign(ref exp) => {
                ret.set(&LuaValue::Integer(next_index), &eval_expr(exp, ctx)?)?;
                next_index = next_index+1;
            },
            nom_lua53::Field::ExpAssign(ref key, ref value) => {
                let key = eval_expr(key, ctx)?;
                let value = eval_expr(value, ctx)?;
                ret.set(&key, &value)?;
            },
            nom_lua53::Field::NameAssign(ref key, ref value) => {
                let key = var_to_string(key);
                let value = eval_expr(value, ctx)?;
                ret.set(&LuaValue::Str(key), &value)?;
            },
            _ => ()
        }
    }
    return Ok(LuaValue::Table(ret));
}

pub fn boolean_coercion(val: &LuaValue) -> bool {
    match *val {
        LuaValue::Nil => false,
        LuaValue::Boolean(b) => b,
        _ => true
    }
}

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

    #[test]
    fn test_boolean_coercion() {
        assert!(boolean_coercion(&LuaValue::Str("".to_owned())));
        assert!(boolean_coercion(&LuaValue::Integer(0)));
        assert!(boolean_coercion(&LuaValue::Integer(2)));
        assert!(!boolean_coercion(&LuaValue::Nil));
        assert!(!boolean_coercion(&LuaValue::Boolean(false)));
        assert!(boolean_coercion(&LuaValue::Boolean(true)));
    }
}

<commit_msg>Remove redundant catchall in the inline table constructor<commit_after>mod binop;
mod unop;

use super::{LuaError, Result, var_to_string};
use super::types::{LuaValue, LuaTable, LuaState};

use nom_lua53;
use std;

// What do we say? We say "Merci Basile!"
fn lit_to_string(string: &nom_lua53::string::StringLit) -> String {
    return String::from_utf8_lossy(&(string.0)).to_string();
}

fn num_coercion(val: LuaValue) -> LuaValue {
    match val {
        LuaValue::Str(s) => {
            let parsed =  str::parse::<isize>(&s);
            match parsed {
                Ok(n) => LuaValue::Integer(n),
                Err(_) => {
                    let parsed =  str::parse::<f64>(&s);
                    match parsed {
                        Ok(n) => LuaValue::Float(n),
                        Err(_) => LuaValue::Str(s)
                    }
                }
            }
        },
        _ => val
    }
}

pub fn eval_expr(expr: &nom_lua53::Exp, ctx: &LuaState) -> Result<LuaValue> {
    match *expr {
        nom_lua53::Exp::Nil => Ok(LuaValue::Nil),
        nom_lua53::Exp::Bool(val) => Ok(LuaValue::Boolean(val)),
        nom_lua53::Exp::Num(val) => Ok(match val {
            nom_lua53::num::Numeral::Float(fl) => LuaValue::Float(fl),
            nom_lua53::num::Numeral::Int(i) => LuaValue::Integer(i),
        }),
        nom_lua53::Exp::BinExp(ref left, ref op, ref right) => binop::eval_binary_expr(left, right, &op, ctx),
        nom_lua53::Exp::UnExp(ref operator, ref operand) => unop::eval_unary_expr(operand, &operator, ctx),
        nom_lua53::Exp::Str(ref s) => Ok(LuaValue::Str(lit_to_string(s))),
        nom_lua53::Exp::Table(ref t) => eval_inline_table(t, ctx),
        nom_lua53::Exp::Ellipses => Err(LuaError::NotImplementedError),
        nom_lua53::Exp::FuncCall(_) => Err(LuaError::NotImplementedError),
        nom_lua53::Exp::Lambda(_) => Err(LuaError::NotImplementedError),
        nom_lua53::Exp::PrefixExp(_) => Err(LuaError::NotImplementedError),
    }
}

fn eval_inline_table(src: &nom_lua53::TableLit, ctx: &LuaState) ->  Result<LuaValue> {
    // First, we count how many positional epxressions there are to only do one allocation.
    let mut sequence_count = 0;
    for field in src.into_iter() {
        match field {
            &nom_lua53::Field::PosAssign(_) => sequence_count = sequence_count+1,
            _ => ()
        }
    }

    let ret = LuaTable::with_capacity(ctx.get_ref_id(), sequence_count);
    let mut next_index = 1;
    for field in src.iter() {
        match *field {
            nom_lua53::Field::PosAssign(ref exp) => {
                ret.set(&LuaValue::Integer(next_index), &eval_expr(exp, ctx)?)?;
                next_index = next_index+1;
            },
            nom_lua53::Field::ExpAssign(ref key, ref value) => {
                let key = eval_expr(key, ctx)?;
                let value = eval_expr(value, ctx)?;
                ret.set(&key, &value)?;
            },
            nom_lua53::Field::NameAssign(ref key, ref value) => {
                let key = var_to_string(key);
                let value = eval_expr(value, ctx)?;
                ret.set(&LuaValue::Str(key), &value)?;
            }
        }
    }
    return Ok(LuaValue::Table(ret));
}

pub fn boolean_coercion(val: &LuaValue) -> bool {
    match *val {
        LuaValue::Nil => false,
        LuaValue::Boolean(b) => b,
        _ => true
    }
}

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

    #[test]
    fn test_boolean_coercion() {
        assert!(boolean_coercion(&LuaValue::Str("".to_owned())));
        assert!(boolean_coercion(&LuaValue::Integer(0)));
        assert!(boolean_coercion(&LuaValue::Integer(2)));
        assert!(!boolean_coercion(&LuaValue::Nil));
        assert!(!boolean_coercion(&LuaValue::Boolean(false)));
        assert!(boolean_coercion(&LuaValue::Boolean(true)));
    }
}
<|endoftext|>


<commit_before>use super::ease::Easing;
/// This struct captures Expo easing functions
pub struct Expo;

impl Easing for Expo {
    fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 {
        if t == 0.0 {
            b
        } else {
            c * 2_f32.powf(10.0 * (t / d - 1.0)) + b
        }
    }

    fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        if t == d {
            b + c
        } else {
            c * (-2_f32.powf(-10.0 * t / d) + 1.0) + b
        }
    }

    fn ease_in_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        if t == 0.0 {
            return b;
        }
        if t == d {
            return b + c;
        }
        let mut inner_t = t / (d / 2.0);
        if inner_t < 1.0 {
            return c / 2.0 * 2_f32.powf(10.0 * (inner_t - 1.0)) + b;
        }
        inner_t -= 1.0;
        return c / 2.0 * (-(2_f32.powf(-10.0 * inner_t)) + 2.0) + b;
    }
}

#[cfg(test)]
mod test {
    #[allow(unused_imports)]
    use functions::ease::Easing;
    #[test]
    fn ease_in() {
        assert_relative_eq!(super::Expo::ease_in(1.0, 2.0, 3.0, 4.0), 2.016573);
        assert_relative_eq!(super::Expo::ease_in(0.0, 1.0, 100.0, 100.0), 1.000000);
    }

    #[test]
    fn ease_out() {
        assert_relative_eq!(super::Expo::ease_out(1.0, 2.0, 3.0, 4.0), 4.469670);
        assert_relative_eq!(super::Expo::ease_out(100.0, 1.0, 100.0, 100.0), 101.0000);
    }

    #[test]
    fn ease_in_out() {
        assert_relative_eq!(super::Expo::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.046875);
        assert_relative_eq!(super::Expo::ease_in_out(0.0, 1.0, 100.0, 100.0), 1.0000);
        assert_relative_eq!(super::Expo::ease_in_out(100.0, 1.0, 100.0, 100.0), 101.000);
        assert_relative_eq!(super::Expo::ease_in_out(51.0, 1.0, 100.0, 100.0), 57.472466);
    }

}
<commit_msg>Clear the Expo easing functions<commit_after>use super::ease::Easing;

/// This struct captures Expo easing functions
pub struct Expo;

impl Easing for Expo {
    fn ease_in(t: f32, b: f32, c: f32, d: f32) -> f32 {
        if t == 0.0 {
            b
        } else {
            c * 2_f32.powf(10.0 * (t / d - 1.0)) + b
        }
    }

    fn ease_out(t: f32, b: f32, c: f32, d: f32) -> f32 {
        if t == d {
            b + c
        } else {
            c * (-2_f32.powf(-10.0 * t / d) + 1.0) + b
        }
    }

    fn ease_in_out(mut t: f32, b: f32, c: f32, d: f32) -> f32 {
        if t == 0.0 {
            return b;
        }
        if t == d {
            return b + c;
        }
        t = t / (d / 2.0);
        if t < 1.0 {
            c / 2.0 * 2_f32.powf(10.0 * (t - 1.0)) + b
        }
        else {
            t -= 1.0;
            c / 2.0 * (-(2_f32.powf(-10.0 * t)) + 2.0) + b
        }
    }
}

#[cfg(test)]
mod test {
    #[allow(unused_imports)]
    use functions::ease::Easing;
    #[test]
    fn ease_in() {
        assert_relative_eq!(super::Expo::ease_in(1.0, 2.0, 3.0, 4.0), 2.016573);
        assert_relative_eq!(super::Expo::ease_in(0.0, 1.0, 100.0, 100.0), 1.000000);
    }

    #[test]
    fn ease_out() {
        assert_relative_eq!(super::Expo::ease_out(1.0, 2.0, 3.0, 4.0), 4.469670);
        assert_relative_eq!(super::Expo::ease_out(100.0, 1.0, 100.0, 100.0), 101.0000);
    }

    #[test]
    fn ease_in_out() {
        assert_relative_eq!(super::Expo::ease_in_out(1.0, 2.0, 3.0, 4.0), 2.046875);
        assert_relative_eq!(super::Expo::ease_in_out(0.0, 1.0, 100.0, 100.0), 1.0000);
        assert_relative_eq!(super::Expo::ease_in_out(100.0, 1.0, 100.0, 100.0), 101.000);
        assert_relative_eq!(super::Expo::ease_in_out(51.0, 1.0, 100.0, 100.0), 57.472466);
    }

}
<|endoftext|>


<commit_before>//! Functions to compress according to the Gzip specification.

use std::io::Write;

use super::Options;

use deflate::deflate;

/// Table of CRCs of all 8-bit messages.
static mut crc_table: [u64; 256] = [0u64; 256];

/// Flag: has the table been computed? Initially false.
static mut crc_table_computed: bool = false;

/// Makes the table for a fast CRC.
unsafe fn make_crc_table() {
    for n in 0..256 {
        let mut c: u64 = n as u64;
        for _ in 0..8 {
            if c & 1 == 1 {
                c = 0xedb88320u64 ^ (c >> 1);
            } else {
                c = c >> 1;
            }
        }
        crc_table[n] = c;
    }
    crc_table_computed = true;
}

/// Updates a running crc with the bytes buf[0..len-1] and returns
/// the updated crc. The crc should be initialized to zero.
unsafe fn update_crc(crc: u64, buf: &[u8]) -> u64 {
    let mut c: u64 = crc ^ 0xffffffffu64;

    if !crc_table_computed {
        make_crc_table();
    }
    for v in buf {
        c = crc_table[((c ^ *v as u64) & 0xff) as usize] ^ (c >> 8);
    }
    c ^ 0xffffffffu64
}

/// Returns the CRC of the bytes buf[0..len-1].
unsafe fn crc(buf: &[u8]) -> u64 {
    update_crc(0u64, buf)
}

/**
 * Compresses according to the gzip specification and append the compressed
 * result to the output.
 *
 * options: global program options
 * out: pointer to the dynamic output array to which the result is appended. Must
 *   be freed after use.
 * outsize: pointer to the dynamic output array size.
 */
pub unsafe fn compress(options: &Options, input: &[u8]) -> Vec<u8> {
    let crcvalue: u64 = crc(input);
    let mut bp: u8 = 0;

    let mut out = Vec::new();
    out.push(31); // ID1
    out.push(139); // ID2
    out.push(8); // CM
    out.push(0); // FLG
    // MTIME
    out.push(0);
    out.push(0);
    out.push(0);
    out.push(0);

    out.push(2); // XFL, 2 indicates best compression.
    out.push(3); // OS follows Unix conventions.

    deflate(options,
            2, // Dynamic block
            true,
            input,
            &mut bp,
            &mut out);

    // CRC
    out.push((crcvalue % 256) as u8);
    out.push(((crcvalue >> 8) % 256) as u8);
    out.push(((crcvalue >> 16) % 256) as u8);
    out.push(((crcvalue >> 24) % 256) as u8);

    // ISIZE
    let insize = input.len();
    out.push((insize % 256) as u8);
    out.push(((insize >> 8) % 256) as u8);
    out.push(((insize >> 16) % 256) as u8);
    out.push(((insize >> 24) % 256) as u8);

    if (*options).verbose {
        let outsize = out.len();
        println_err!("Original Size: {}, Gzip: {}, Compression: {}% Removed",
                     insize,
                     outsize,
                     100.0 * (insize as isize - outsize as isize) as f64 / insize as f64);
    }
    out
}
<commit_msg>Remove global crc table to eliminate unsafe code<commit_after>//! Functions to compress according to the Gzip specification.

use std::io::Write;

use super::Options;

use deflate::deflate;

struct CRC {
    /// Table of CRCs of all 8-bit messages.
    table: [u64; 256]
}

impl CRC {
    /// Makes the table for a fast CRC.
    fn new() -> CRC {
        let mut table = [0u64; 256];
        for n in 0..256 {
            let mut c: u64 = n as u64;
            for _ in 0..8 {
                if c & 1 == 1 {
                    c = 0xedb88320u64 ^ (c >> 1);
                } else {
                    c = c >> 1;
                }
            }
            table[n] = c;
        }
        CRC { table: table }
    }

    /// Updates a running crc with the bytes buf[0..len-1] and returns
    /// the updated crc. The crc should be initialized to zero.
    fn update(&self, crc: u64, buf: &[u8]) -> u64 {
        let mut c: u64 = crc ^ 0xffffffffu64;

        for v in buf {
            c = self.table[((c ^ *v as u64) & 0xff) as usize] ^ (c >> 8);
        }
        c ^ 0xffffffffu64
    }

    /// Returns the CRC of the bytes buf[0..len-1].
    fn calc(&self, buf: &[u8]) -> u64 {
        self.update(0u64, buf)
    }
}

/**
 * Compresses according to the gzip specification and append the compressed
 * result to the output.
 *
 * options: global program options
 * out: pointer to the dynamic output array to which the result is appended. Must
 *   be freed after use.
 * outsize: pointer to the dynamic output array size.
 */
pub fn compress(options: &Options, input: &[u8]) -> Vec<u8> {
    let crc = CRC::new();
    let crcvalue: u64 = crc.calc(input);
    let mut bp: u8 = 0;

    let mut out = Vec::new();
    out.push(31); // ID1
    out.push(139); // ID2
    out.push(8); // CM
    out.push(0); // FLG
    // MTIME
    out.push(0);
    out.push(0);
    out.push(0);
    out.push(0);

    out.push(2); // XFL, 2 indicates best compression.
    out.push(3); // OS follows Unix conventions.

    deflate(options,
            2, // Dynamic block
            true,
            input,
            &mut bp,
            &mut out);

    // CRC
    out.push((crcvalue % 256) as u8);
    out.push(((crcvalue >> 8) % 256) as u8);
    out.push(((crcvalue >> 16) % 256) as u8);
    out.push(((crcvalue >> 24) % 256) as u8);

    // ISIZE
    let insize = input.len();
    out.push((insize % 256) as u8);
    out.push(((insize >> 8) % 256) as u8);
    out.push(((insize >> 16) % 256) as u8);
    out.push(((insize >> 24) % 256) as u8);

    if options.verbose {
        let outsize = out.len();
        println_err!("Original Size: {}, Gzip: {}, Compression: {}% Removed",
                     insize,
                     outsize,
                     100.0 * (insize as isize - outsize as isize) as f64 / insize as f64);
    }
    out
}
<|endoftext|>