<commit_before>use std::iter::FromIterator;

use num::{Zero, One};

use number::Number;
use error::{RuntimeError, RuntimeErrorKind};
use runtime::{DatumCast, RDatum, DatumType};

pub trait PrimFunc {
    fn call(&self, &[RDatum]) -> Result<RDatum, RuntimeError>;
}

pub struct Fold<P> {
    fold: fn(&[P]) -> P
}

#[derive(Copy)]
pub struct FoldDatum {
    fold: fn(&[RDatum]) -> RDatum
}

pub struct Fold1<P> {
    fold1: fn(&P, &[P]) -> P
}

pub struct Fold1Err<P> {
    fold1: fn(&P, &[P]) -> Result<P, RuntimeError>
}

#[derive(Copy)]
pub struct Pred {
    pred: fn(&RDatum) -> bool
}

impl<T> PrimFunc for Fold<T> where T: DatumCast {
    fn call(&self, args: &[RDatum]) -> Result<RDatum, RuntimeError> {
        let p_args:Result<Vec<T>, RuntimeError> = args.iter().map(DatumCast::unwrap).collect();
        let f = self.fold;
        p_args.map(|v| f(v.as_slice()).wrap())
    }
}

impl PrimFunc for FoldDatum {
    fn call(&self, args: &[RDatum]) -> Result<RDatum, RuntimeError> {
        let f = self.fold;
        Ok(f(args))
    }
}

impl<T> PrimFunc for Fold1<T> where T: DatumCast {
    fn call(&self, args: &[RDatum]) -> Result<RDatum, RuntimeError> {
        let p_args:Result<Vec<T>, RuntimeError> = args.iter().map(DatumCast::unwrap).collect();
        let f = self.fold1;
        p_args.and_then(|v|
            if v.len() < 1 {
                Err(RuntimeError {
                    kind: RuntimeErrorKind::NumArgs,
                    desc: "Expected at least 1 arguments, received 0".to_string()
                })
            } else {
                Ok(f(&v[0], &v[1..]).wrap())
            }
        )
    }
}

impl<T> PrimFunc for Fold1Err<T> where T: DatumCast {
    fn call(&self, args: &[RDatum]) -> Result<RDatum, RuntimeError> {
        let p_args:Result<Vec<T>, RuntimeError> = args.iter().map(DatumCast::unwrap).collect();
        let f = self.fold1;
        p_args.and_then(|v|
            if v.len() < 1 {
                Err(RuntimeError {
                    kind: RuntimeErrorKind::NumArgs,
                    desc: "Expected at least 1 arguments, received 0".to_string()
                })
            } else {
                f(&v[0], &v[1..]).map(|res| res.wrap())
            }
        )
    }
}

impl PrimFunc for Pred {
    fn call(&self, args: &[RDatum]) -> Result<RDatum, RuntimeError> {
        if args.len() != 1 {
            return Err(RuntimeError {
                kind: RuntimeErrorKind::NumArgs,
                desc: format!("Expected 1 argument, received {:?}", args.len())
            });
        }
        let f = self.pred;

        Ok(f(&args[0]).wrap())
    }
}

fn add(args: &[Number]) -> Number {
    let mut sum:Number = Zero::zero();
    for a in args.iter() {
        sum = &sum + a;
    }
    return sum;
}

/// `(+ n0 n1 ...)`
pub static PRIM_ADD:Fold<Number> = Fold { fold: add };

fn mul(args: &[Number]) -> Number {
    let mut product:Number = One::one();
    for a in args.iter() {
        product = &product * a;
    }
    return product;
}

/// `(* n0 n1 ...)`
pub static PRIM_MUL:Fold<Number> = Fold { fold: mul };

fn sub(arg0: &Number, args: &[Number]) -> Number {
    if args.len() == 0 {
        return -arg0;
    }
    let mut sum:Number = arg0.clone();
    for a in args.iter() {
        sum = &sum - a;
    }
    return sum;
}

/// `(- n0 n1 ...)`
pub static PRIM_SUB:Fold1<Number> = Fold1 { fold1: sub };

fn div(arg0: &Number, args: &[Number]) -> Result<Number, RuntimeError> {
    if args.len() == 0 {
        if arg0.is_exact() && arg0.is_zero() {
            return Err(RuntimeError {
                kind: RuntimeErrorKind::DivideByZero,
                desc: "Tried to divied by 0".to_string()
            });
        }
        return Ok(-arg0);
    }

    let mut product:Number = arg0.clone();
    for a in args.iter() {
        if a.is_exact() && a.is_zero() {
            return Err(RuntimeError {
                kind: RuntimeErrorKind::DivideByZero,
                desc: "Tried to divied by 0".to_string()
            });
        }
        product = &product / a;
    }

    return Ok(product);
}

/// `(/ n0 n1 ...)`
pub static PRIM_DIV:Fold1Err<Number> = Fold1Err { fold1: div };

fn list(args: &[RDatum]) -> RDatum {
    FromIterator::from_iter(args.iter().map(Clone::clone))
}

pub static PRIM_LIST:FoldDatum = FoldDatum { fold: list };

macro_rules! impl_typecheck {
    ($static_name:ident, $func_name:ident, $type_name:ident) => (
        fn $func_name(arg: &RDatum) -> bool {
            DatumType::get_type(arg) == DatumType::$type_name
        }

        pub static $static_name: Pred = Pred { pred: $func_name };
    )
}

impl_typecheck!(PRIM_BOOLEAN, is_boolean, Bool);
impl_typecheck!(PRIM_PAIR, is_pair, Pair);
impl_typecheck!(PRIM_SYMBOL, is_symbol, Sym);
impl_typecheck!(PRIM_NUMBER, is_number, Num);
impl_typecheck!(PRIM_CHAR, is_char, Char);
impl_typecheck!(PRIM_STRING, is_string, String);
impl_typecheck!(PRIM_PROCEDURE, is_procedure, Callable);
impl_typecheck!(PRIM_NULL, is_null, Null);

/// Lists all primitive functions with its name
pub fn libprimitive() -> Vec<(&'static str, &'static (PrimFunc + 'static))> {
    vec![
        ("+", &PRIM_ADD),
        ("-", &PRIM_SUB),
        ("*", &PRIM_MUL),
        ("/", &PRIM_DIV),
        ("list", &PRIM_LIST),
        ("boolean?", &PRIM_BOOLEAN),
        ("pair?", &PRIM_PAIR),
        ("symbol?", &PRIM_SYMBOL),
        ("number?", &PRIM_NUMBER),
        ("char?", &PRIM_CHAR),
        ("string?", &PRIM_STRING),
        ("procedure?", &PRIM_PROCEDURE),
        ("null?", &PRIM_NULL)
    ]
}
<commit_msg>Generalize Pred into F1<Datum, bool><commit_after>use std::iter::FromIterator;

use num::{Zero, One};

use number::Number;
use error::{RuntimeError, RuntimeErrorKind};
use runtime::{DatumCast, RDatum, DatumType};

pub trait PrimFunc {
    fn call(&self, &[RDatum]) -> Result<RDatum, RuntimeError>;
}

pub struct Fold<P> {
    fold: fn(&[P]) -> P
}

#[derive(Copy)]
pub struct FoldDatum {
    fold: fn(&[RDatum]) -> RDatum
}

pub struct Fold1<P> {
    fold1: fn(&P, &[P]) -> P
}

pub struct Fold1Err<P> {
    fold1: fn(&P, &[P]) -> Result<P, RuntimeError>
}

pub struct F1<T0, R> {
    f1: fn(&T0) -> R
}

impl<T> PrimFunc for Fold<T> where T: DatumCast {
    fn call(&self, args: &[RDatum]) -> Result<RDatum, RuntimeError> {
        let p_args:Result<Vec<T>, RuntimeError> = args.iter().map(DatumCast::unwrap).collect();
        let f = self.fold;
        p_args.map(|v| f(v.as_slice()).wrap())
    }
}

impl PrimFunc for FoldDatum {
    fn call(&self, args: &[RDatum]) -> Result<RDatum, RuntimeError> {
        let f = self.fold;
        Ok(f(args))
    }
}

impl<T> PrimFunc for Fold1<T> where T: DatumCast {
    fn call(&self, args: &[RDatum]) -> Result<RDatum, RuntimeError> {
        let p_args:Result<Vec<T>, RuntimeError> = args.iter().map(DatumCast::unwrap).collect();
        let f = self.fold1;
        p_args.and_then(|v|
            if v.len() < 1 {
                Err(RuntimeError {
                    kind: RuntimeErrorKind::NumArgs,
                    desc: "Expected at least 1 arguments, received 0".to_string()
                })
            } else {
                Ok(f(&v[0], &v[1..]).wrap())
            }
        )
    }
}

impl<T> PrimFunc for Fold1Err<T> where T: DatumCast {
    fn call(&self, args: &[RDatum]) -> Result<RDatum, RuntimeError> {
        let p_args:Result<Vec<T>, RuntimeError> = args.iter().map(DatumCast::unwrap).collect();
        let f = self.fold1;
        p_args.and_then(|v|
            if v.len() < 1 {
                Err(RuntimeError {
                    kind: RuntimeErrorKind::NumArgs,
                    desc: "Expected at least 1 arguments, received 0".to_string()
                })
            } else {
                f(&v[0], &v[1..]).map(|res| res.wrap())
            }
        )
    }
}

impl<R: DatumCast> PrimFunc for F1<RDatum, R> {
    fn call(&self, args: &[RDatum]) -> Result<RDatum, RuntimeError> {
        if args.len() != 1 {
            return Err(RuntimeError {
                kind: RuntimeErrorKind::NumArgs,
                desc: format!("Expected 1 argument, received {:?}", args.len())
            });
        }
        let f = self.f1;

        Ok(f(&args[0]).wrap())
    }
}

fn add(args: &[Number]) -> Number {
    let mut sum:Number = Zero::zero();
    for a in args.iter() {
        sum = &sum + a;
    }
    return sum;
}

/// `(+ n0 n1 ...)`
pub static PRIM_ADD:Fold<Number> = Fold { fold: add };

fn mul(args: &[Number]) -> Number {
    let mut product:Number = One::one();
    for a in args.iter() {
        product = &product * a;
    }
    return product;
}

/// `(* n0 n1 ...)`
pub static PRIM_MUL:Fold<Number> = Fold { fold: mul };

fn sub(arg0: &Number, args: &[Number]) -> Number {
    if args.len() == 0 {
        return -arg0;
    }
    let mut sum:Number = arg0.clone();
    for a in args.iter() {
        sum = &sum - a;
    }
    return sum;
}

/// `(- n0 n1 ...)`
pub static PRIM_SUB:Fold1<Number> = Fold1 { fold1: sub };

fn div(arg0: &Number, args: &[Number]) -> Result<Number, RuntimeError> {
    if args.len() == 0 {
        if arg0.is_exact() && arg0.is_zero() {
            return Err(RuntimeError {
                kind: RuntimeErrorKind::DivideByZero,
                desc: "Tried to divied by 0".to_string()
            });
        }
        return Ok(-arg0);
    }

    let mut product:Number = arg0.clone();
    for a in args.iter() {
        if a.is_exact() && a.is_zero() {
            return Err(RuntimeError {
                kind: RuntimeErrorKind::DivideByZero,
                desc: "Tried to divied by 0".to_string()
            });
        }
        product = &product / a;
    }

    return Ok(product);
}

/// `(/ n0 n1 ...)`
pub static PRIM_DIV:Fold1Err<Number> = Fold1Err { fold1: div };

fn list(args: &[RDatum]) -> RDatum {
    FromIterator::from_iter(args.iter().map(Clone::clone))
}

pub static PRIM_LIST:FoldDatum = FoldDatum { fold: list };

macro_rules! impl_typecheck {
    ($static_name:ident, $func_name:ident, $type_name:ident) => (
        fn $func_name(arg: &RDatum) -> bool {
            DatumType::get_type(arg) == DatumType::$type_name
        }

        pub static $static_name: F1<RDatum, bool> = F1 { f1: $func_name };
    )
}

impl_typecheck!(PRIM_BOOLEAN, is_boolean, Bool);
impl_typecheck!(PRIM_PAIR, is_pair, Pair);
impl_typecheck!(PRIM_SYMBOL, is_symbol, Sym);
impl_typecheck!(PRIM_NUMBER, is_number, Num);
impl_typecheck!(PRIM_CHAR, is_char, Char);
impl_typecheck!(PRIM_STRING, is_string, String);
impl_typecheck!(PRIM_PROCEDURE, is_procedure, Callable);
impl_typecheck!(PRIM_NULL, is_null, Null);

/// Lists all primitive functions with its name
pub fn libprimitive() -> Vec<(&'static str, &'static (PrimFunc + 'static))> {
    vec![
        ("+", &PRIM_ADD),
        ("-", &PRIM_SUB),
        ("*", &PRIM_MUL),
        ("/", &PRIM_DIV),
        ("list", &PRIM_LIST),
        ("boolean?", &PRIM_BOOLEAN),
        ("pair?", &PRIM_PAIR),
        ("symbol?", &PRIM_SYMBOL),
        ("number?", &PRIM_NUMBER),
        ("char?", &PRIM_CHAR),
        ("string?", &PRIM_STRING),
        ("procedure?", &PRIM_PROCEDURE),
        ("null?", &PRIM_NULL)
    ]
}
<|endoftext|>


<commit_before>#![allow(unused)]

//! Implements a map from integer indices to data.
//! Rather than storing data for every index, internally, this maps entire ranges to the data.
//! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as
//! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated).
//! Users must not depend on whether a range is coalesced or not, even though this is observable
//! via the iteration APIs.
use std::collections::BTreeMap;
use std::ops;

use rustc::ty::layout::Size;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RangeMap<T> {
    map: BTreeMap<Range, T>,
}

// The derived `Ord` impl sorts first by the first field, then, if the fields are the same,
// by the second field.
// This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all
// `MemoryRange`s whose `start` is <= than the one we're looking for, but not > the end of the range we're checking.
// At the same time the `end` is irrelevant for the sorting and range searching, but used for the check.
// This kind of search breaks, if `end < start`, so don't do that!
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
struct Range {
    start: u64,
    end: u64, // Invariant: end > start
}

impl Range {
    /// Compute a range of ranges that contains all ranges overlaping with [offset, offset+len)
    fn range(offset: u64, len: u64) -> ops::Range<Range> {
        if len == 0 {
            // We can produce an empty range, nothing overlaps with this.
            let r = Range { start: 0, end: 1 };
            return r..r;
        }
        // We select all elements that are within
        // the range given by the offset into the allocation and the length.
        // This is sound if all ranges that intersect with the argument range, are in the
        // resulting range of ranges.
        let left = Range {
            // lowest range to include `offset`
            start: 0,
            end: offset + 1,
        };
        let right = Range {
            // lowest (valid) range not to include `offset+len`
            start: offset + len,
            end: offset + len + 1,
        };
        left..right
    }

    /// Tests if any element of [offset, offset+len) is contained in this range.
    #[inline(always)]
    fn overlaps(&self, offset: u64, len: u64) -> bool {
        if len == 0 {
            // `offset` totally does not matter, we cannot overlap with an empty interval
            false
        } else {
            offset < self.end && offset.checked_add(len).unwrap() >= self.start
        }
    }
}

impl<T> RangeMap<T> {
    /// Create a new RangeMap for the given size, and with the given initial value used for
    /// the entire range.
    #[inline(always)]
    pub fn new(size: Size, init: T) -> RangeMap<T> {
        let mut map = RangeMap { map: BTreeMap::new() };
        if size.bytes() > 0 {
            map.map.insert(Range { start: 0, end: size.bytes() }, init);
        }
        map
    }

    fn iter_with_range<'a>(
        &'a self,
        offset: u64,
        len: u64,
    ) -> impl Iterator<Item = (&'a Range, &'a T)> + 'a {
        self.map.range(Range::range(offset, len)).filter_map(
            move |(range, data)| {
                debug_assert!(len > 0);
                if range.overlaps(offset, len) {
                    Some((range, data))
                } else {
                    None
                }
            },
        )
    }

    /// Provide read-only iteration over everything in the given range.  This does
    /// *not* split items if they overlap with the edges.  Do not use this to mutate
    /// through interior mutability.
    pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator<Item = &'a T> + 'a {
        self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data)
    }

    pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator<Item = &'a mut T> + 'a {
        self.map.values_mut()
    }

    fn split_entry_at(&mut self, offset: u64)
    where
        T: Clone,
    {
        let range = match self.iter_with_range(offset, 1).next() {
            Some((&range, _)) => range,
            None => return,
        };
        assert!(
            range.start <= offset && range.end > offset,
            "We got a range that doesn't even contain what we asked for."
        );
        // There is an entry overlapping this position, see if we have to split it
        if range.start < offset {
            let data = self.map.remove(&range).unwrap();
            let old = self.map.insert(
                Range {
                    start: range.start,
                    end: offset,
                },
                data.clone(),
            );
            assert!(old.is_none());
            let old = self.map.insert(
                Range {
                    start: offset,
                    end: range.end,
                },
                data,
            );
            assert!(old.is_none());
        }
    }

    /// Provide mutable iteration over everything in the given range.  As a side-effect,
    /// this will split entries in the map that are only partially hit by the given range,
    /// to make sure that when they are mutated, the effect is constrained to the given range.
    pub fn iter_mut<'a>(
        &'a mut self,
        offset: Size,
        len: Size,
    ) -> impl Iterator<Item = &'a mut T> + 'a
    where
        T: Clone,
    {
        let offset = offset.bytes();
        let len = len.bytes();

        if len > 0 {
            // Preparation: Split first and last entry as needed.
            self.split_entry_at(offset);
            self.split_entry_at(offset + len);
        }
        // Now we can provide a mutable iterator
        self.map.range_mut(Range::range(offset, len)).filter_map(
            move |(&range, data)| {
                debug_assert!(len > 0);
                if range.overlaps(offset, len) {
                    assert!(
                        offset <= range.start && offset + len >= range.end,
                        "The splitting went wrong"
                    );
                    Some(data)
                } else {
                    // Skip this one
                    None
                }
            },
        )
    }
}

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

    /// Query the map at every offset in the range and collect the results.
    fn to_vec<T: Copy>(map: &RangeMap<T>, offset: u64, len: u64) -> Vec<T> {
        (offset..offset + len)
            .into_iter()
            .map(|i| map
                .iter(Size::from_bytes(i), Size::from_bytes(1))
                .next()
                .map(|&t| t)
                .unwrap()
            )
            .collect()
    }

    #[test]
    fn basic_insert() {
        let mut map = RangeMap::<i32>::new(Size::from_bytes(20), -1);
        // Insert
        for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) {
            *x = 42;
        }
        // Check
        assert_eq!(to_vec(&map, 10, 1), vec![42]);

        // Insert with size 0
        for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) {
            *x = 19;
        }
        for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) {
            *x = 19;
        }
        assert_eq!(to_vec(&map, 10, 2), vec![42, -1]);
    }

    #[test]
    fn gaps() {
        let mut map = RangeMap::<i32>::new(Size::from_bytes(20), -1);
        for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) {
            *x = 42;
        }
        for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) {
            *x = 43;
        }
        assert_eq!(
            to_vec(&map, 10, 10),
            vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1]
        );

        for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) {
            if *x < 42 {
                *x = 23;
            }
        }

        assert_eq!(
            to_vec(&map, 10, 10),
            vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23]
        );
        assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]);

        // Now request a range that goes beyond the initial size
        for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(10)) {
            *x = 19;
        }
        assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1))
            .map(|&t| t).collect::<Vec<_>>(), vec![19]);
        assert_eq!(map.iter(Size::from_bytes(20), Size::from_bytes(1))
            .map(|&t| t).collect::<Vec<_>>(), vec![]);
    }
}
<commit_msg>range_map: also test size of the internal representation<commit_after>#![allow(unused)]

//! Implements a map from integer indices to data.
//! Rather than storing data for every index, internally, this maps entire ranges to the data.
//! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as
//! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated).
//! Users must not depend on whether a range is coalesced or not, even though this is observable
//! via the iteration APIs.
use std::collections::BTreeMap;
use std::ops;

use rustc::ty::layout::Size;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RangeMap<T> {
    map: BTreeMap<Range, T>,
}

// The derived `Ord` impl sorts first by the first field, then, if the fields are the same,
// by the second field.
// This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all
// `MemoryRange`s whose `start` is <= than the one we're looking for, but not > the end of the range we're checking.
// At the same time the `end` is irrelevant for the sorting and range searching, but used for the check.
// This kind of search breaks, if `end < start`, so don't do that!
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
struct Range {
    start: u64,
    end: u64, // Invariant: end > start
}

impl Range {
    /// Compute a range of ranges that contains all ranges overlaping with [offset, offset+len)
    fn range(offset: u64, len: u64) -> ops::Range<Range> {
        if len == 0 {
            // We can produce an empty range, nothing overlaps with this.
            let r = Range { start: 0, end: 1 };
            return r..r;
        }
        // We select all elements that are within
        // the range given by the offset into the allocation and the length.
        // This is sound if all ranges that intersect with the argument range, are in the
        // resulting range of ranges.
        let left = Range {
            // lowest range to include `offset`
            start: 0,
            end: offset + 1,
        };
        let right = Range {
            // lowest (valid) range not to include `offset+len`
            start: offset + len,
            end: offset + len + 1,
        };
        left..right
    }

    /// Tests if any element of [offset, offset+len) is contained in this range.
    #[inline(always)]
    fn overlaps(&self, offset: u64, len: u64) -> bool {
        if len == 0 {
            // `offset` totally does not matter, we cannot overlap with an empty interval
            false
        } else {
            offset < self.end && offset.checked_add(len).unwrap() >= self.start
        }
    }
}

impl<T> RangeMap<T> {
    /// Create a new RangeMap for the given size, and with the given initial value used for
    /// the entire range.
    #[inline(always)]
    pub fn new(size: Size, init: T) -> RangeMap<T> {
        let mut map = RangeMap { map: BTreeMap::new() };
        if size.bytes() > 0 {
            map.map.insert(Range { start: 0, end: size.bytes() }, init);
        }
        map
    }

    fn iter_with_range<'a>(
        &'a self,
        offset: u64,
        len: u64,
    ) -> impl Iterator<Item = (&'a Range, &'a T)> + 'a {
        self.map.range(Range::range(offset, len)).filter_map(
            move |(range, data)| {
                debug_assert!(len > 0);
                if range.overlaps(offset, len) {
                    Some((range, data))
                } else {
                    None
                }
            },
        )
    }

    /// Provide read-only iteration over everything in the given range.  This does
    /// *not* split items if they overlap with the edges.  Do not use this to mutate
    /// through interior mutability.
    pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator<Item = &'a T> + 'a {
        self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data)
    }

    pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator<Item = &'a mut T> + 'a {
        self.map.values_mut()
    }

    fn split_entry_at(&mut self, offset: u64)
    where
        T: Clone,
    {
        let range = match self.iter_with_range(offset, 1).next() {
            Some((&range, _)) => range,
            None => return,
        };
        assert!(
            range.start <= offset && range.end > offset,
            "We got a range that doesn't even contain what we asked for."
        );
        // There is an entry overlapping this position, see if we have to split it
        if range.start < offset {
            let data = self.map.remove(&range).unwrap();
            let old = self.map.insert(
                Range {
                    start: range.start,
                    end: offset,
                },
                data.clone(),
            );
            assert!(old.is_none());
            let old = self.map.insert(
                Range {
                    start: offset,
                    end: range.end,
                },
                data,
            );
            assert!(old.is_none());
        }
    }

    /// Provide mutable iteration over everything in the given range.  As a side-effect,
    /// this will split entries in the map that are only partially hit by the given range,
    /// to make sure that when they are mutated, the effect is constrained to the given range.
    pub fn iter_mut<'a>(
        &'a mut self,
        offset: Size,
        len: Size,
    ) -> impl Iterator<Item = &'a mut T> + 'a
    where
        T: Clone,
    {
        let offset = offset.bytes();
        let len = len.bytes();

        if len > 0 {
            // Preparation: Split first and last entry as needed.
            self.split_entry_at(offset);
            self.split_entry_at(offset + len);
        }
        // Now we can provide a mutable iterator
        self.map.range_mut(Range::range(offset, len)).filter_map(
            move |(&range, data)| {
                debug_assert!(len > 0);
                if range.overlaps(offset, len) {
                    assert!(
                        offset <= range.start && offset + len >= range.end,
                        "The splitting went wrong"
                    );
                    Some(data)
                } else {
                    // Skip this one
                    None
                }
            },
        )
    }
}

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

    /// Query the map at every offset in the range and collect the results.
    fn to_vec<T: Copy>(map: &RangeMap<T>, offset: u64, len: u64) -> Vec<T> {
        (offset..offset + len)
            .into_iter()
            .map(|i| map
                .iter(Size::from_bytes(i), Size::from_bytes(1))
                .next()
                .map(|&t| t)
                .unwrap()
            )
            .collect()
    }

    #[test]
    fn basic_insert() {
        let mut map = RangeMap::<i32>::new(Size::from_bytes(20), -1);
        // Insert
        for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) {
            *x = 42;
        }
        // Check
        assert_eq!(to_vec(&map, 10, 1), vec![42]);
        assert_eq!(map.map.len(), 3);

        // Insert with size 0
        for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) {
            *x = 19;
        }
        for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) {
            *x = 19;
        }
        assert_eq!(to_vec(&map, 10, 2), vec![42, -1]);
        assert_eq!(map.map.len(), 3);
    }

    #[test]
    fn gaps() {
        let mut map = RangeMap::<i32>::new(Size::from_bytes(20), -1);
        for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) {
            *x = 42;
        }
        for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) {
            *x = 43;
        }
        assert_eq!(map.map.len(), 5);
        assert_eq!(
            to_vec(&map, 10, 10),
            vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1]
        );

        for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) {
            if *x < 42 {
                *x = 23;
            }
        }
        assert_eq!(map.map.len(), 6);

        assert_eq!(
            to_vec(&map, 10, 10),
            vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23]
        );
        assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]);

        // Now request a range that goes beyond the initial size
        for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(10)) {
            *x = 19;
        }
        assert_eq!(map.map.len(), 6);
        assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1))
            .map(|&t| t).collect::<Vec<_>>(), vec![19]);
        assert_eq!(map.iter(Size::from_bytes(20), Size::from_bytes(1))
            .map(|&t| t).collect::<Vec<_>>(), vec![]);
    }
}
<|endoftext|>


<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// Applies two terms with substitution and variable update, consuming the first one in the process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming it
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self) {
        let mut done = false;
        self._beta_once(&mut done, 0);
    }

    fn _beta_once(&mut self, done: &mut bool, depth: u32) {
        if *done { return }

        match *self {
            Var(_) => (),
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once(done, depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    let copy = self.clone();
                    if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
                    *self = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth + 1)) }
                    *done = true;
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once(done, depth);
                    self.rhs_ref_mut().unwrap()._beta_once(done, depth)
                }
            }
        }
    }

    /// Performs full normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp;
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full normal-order β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single normal-order β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

#[cfg(test)]
mod test {

}
<commit_msg>a slight improvement in classic display mode<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// Applies two terms with substitution and variable update, consuming the first one in the process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming it
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self) {
        let mut done = false;
        self._beta_once(&mut done, 0);
    }

    fn _beta_once(&mut self, done: &mut bool, depth: u32) {
        if *done { return }

        match *self {
            Var(_) => (),
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once(done, depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    let copy = self.clone();
                    if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
                    *self = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
                    *done = true;
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once(done, depth);
                    self.rhs_ref_mut().unwrap()._beta_once(done, depth)
                }
            }
        }
    }

    /// Performs full normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp;
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full normal-order β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single normal-order β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

#[cfg(test)]
mod test {

}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! Scene infrastructure to be used with Gfx phases.

extern crate gfx_phase;
extern crate gfx;
extern crate cgmath;

use std::cmp::Ordering;
use std::fmt::Debug;
use std::marker::PhantomData;

mod cull;
mod harness;

pub use self::cull::CullPhase;
pub use self::harness::PhaseHarness;

/// Scene drawing error.
#[derive(Debug)]
pub enum Error {
    /// Error in creating a batch.
    Batch(gfx::batch::Error),
    /// Error in sending a batch for drawing.
    Flush(gfx_phase::FlushError),
}

/// Abstract information about the view. Supposed to containt at least
/// Model-View-Projection transform for the shader.
pub trait ViewInfo<S, T: cgmath::Transform3<S>>: gfx_phase::ToDepth<Depth = S> {
    /// Construct a new information block.
    fn new(mvp: cgmath::Matrix4<S>, view: T, model: T) -> Self;
}

/// Abstract scene that can be drawn into something.
pub trait AbstractScene<R: gfx::Resources> {
    /// A type of the view information.
    type ViewInfo;
    /// A type of the entity.
    type Entity;
    /// A type of the camera.
    type Camera;

    /// Draw the contents of the scene with a specific phase into a renderer,
    /// using a given camera and a frame.
    fn draw<
        C: gfx::CommandBuffer<R>,
        H: gfx_phase::AbstractPhase<R, C, Self::Entity, Self::ViewInfo> + ?Sized,
    >(
        &self, &mut H, &Self::Camera, &gfx::Frame<R>, &mut gfx::Renderer<R, C>)
        -> Result<(), Error>;
}

/// An extension to `AbstractScene` that allows custom ordering of batches.
pub trait OrderedScene<R: gfx::Resources>: AbstractScene<R> {
    /// Draw the contents with a specific phase, given the ordering function.
    fn draw_ordered<
        C: gfx::CommandBuffer<R>,
        H: gfx_phase::AbstractPhase<R, C, Self::Entity, Self::ViewInfo> + ?Sized +
            gfx_phase::Ordered,
        F: Fn(&H::Object, &H::Object) -> Ordering,
    >(
        &self, &mut H, order: F, &Self::Camera, &gfx::Frame<R>, &mut gfx::Renderer<R, C>)
        -> Result<(), Error>;
}

/// A class that manages spatial relations between objects.
pub trait World {
    /// Type of the scalar used in all associated mathematical constructs.
    type Scalar: cgmath::BaseFloat + 'static;
    /// Type of the transform that every node performs relative to the parent.
    type Transform: cgmath::Transform3<Self::Scalar> + Clone;
    /// Pointer to a node, associated with an entity, camera, or something else.
    type NodePtr;
    /// Pointer to a skeleton, associated with an enttity.
    type SkeletonPtr;
    /// Get the transformation of a specific node pointer.
    fn get_transform(&self, &Self::NodePtr) -> Self::Transform;
}

/// A simple struct representing an object with a given material, mesh, bound,
/// and spatial relation to other stuff in the world.
pub struct Entity<R: gfx::Resources, M, W: World, B> {
    /// Name of the entity.
    pub name: String,
    /// Assotiated material of the entity.
    pub material: M,
    /// Mesh.
    pub mesh: gfx::Mesh<R>,
    /// Mesh slice.
    pub slice: gfx::Slice<R>,
    /// Node pointer into the world.
    pub node: W::NodePtr,
    /// Skeleton pointer.
    pub skeleton: Option<W::SkeletonPtr>,
    /// Associated spatial bound of the entity.
    pub bound: B,
}

impl<R: gfx::Resources, M: gfx_phase::Material, W: World, B> gfx_phase::Entity<R, M> for Entity<R, M, W, B> {
    fn get_material(&self) -> &M {
        &self.material
    }
    fn get_mesh(&self) -> (&gfx::Mesh<R>, &gfx::Slice<R>) {
        (&self.mesh, &self.slice)
    }
}

/// A simple camera with generic projection and spatial relation.
#[derive(Clone, Debug)]
pub struct Camera<P, N> {
    /// Name of the camera.
    pub name: String,
    /// Generic projection.
    pub projection: P,
    /// Generic spatial node.
    pub node: N,
}

/// An example scene type.
pub struct Scene<R: gfx::Resources, M, W: World, B, P, V> {
    /// A list of entities in the scene.
    pub entities: Vec<Entity<R, M, W, B>>,
    /// A list of cameras. It's not really useful, but `P` needs to be
    /// constrained in order to be able to implement `AbstractScene`.
    pub cameras: Vec<Camera<P, W::NodePtr>>,
    /// A flag controlling the frustum culling.
    pub cull_frustum: bool,
    /// Spatial world.
    pub world: W,
    _view_dummy: PhantomData<V>,
}

impl<R: gfx::Resources, M, W: World, B, P, V> Scene<R, M, W, B, P, V> {
    /// Create a new empty scene.
    pub fn new(world: W) -> Scene<R, M, W, B, P, V> {
        Scene {
            entities: Vec::new(),
            cameras: Vec::new(),
            cull_frustum: true,
            world: world,
            _view_dummy: PhantomData,
        }
    }
}

impl<
    R: gfx::Resources,
    M: gfx_phase::Material,
    W: World,
    B: cgmath::Bound<W::Scalar> + Debug,
    P: cgmath::Projection<W::Scalar>,
    V: ViewInfo<W::Scalar, W::Transform>,
> AbstractScene<R> for Scene<R, M, W, B, P, V> {
    type ViewInfo = V;
    type Entity = Entity<R, M, W, B>;
    type Camera = Camera<P, W::NodePtr>;

    fn draw<
        C: gfx::CommandBuffer<R>,
        H: gfx_phase::AbstractPhase<R, C, Entity<R, M, W, B>, V> + ?Sized,
    >(  &self, phase: &mut H, camera: &Camera<P, W::NodePtr>,
        frame: &gfx::Frame<R>, renderer: &mut gfx::Renderer<R, C>)
        -> Result<(), Error>
    {
        // enqueue entities
        match phase.enqueue_all(self.entities.iter(), &self.world, camera,
                                self.cull_frustum) {
            Ok(()) => (),
            Err(e) => return Err(Error::Batch(e)),
        };
        // sort by default criterias
        phase.sort();
        // flush into the renderer
        phase.flush(frame, renderer).map_err(|e| Error::Flush(e))
    }
}

impl<
    R: gfx::Resources,
    M: gfx_phase::Material,
    W: World,
    B: cgmath::Bound<W::Scalar> + Debug,
    P: cgmath::Projection<W::Scalar>,
    V: ViewInfo<W::Scalar, W::Transform>,
> OrderedScene<R> for Scene<R, M, W, B, P, V> {
    fn draw_ordered<
        C: gfx::CommandBuffer<R>,
        H: gfx_phase::AbstractPhase<R, C, Entity<R, M, W, B>, V> + ?Sized +
            gfx_phase::Ordered,
        F: Fn(&H::Object, &H::Object) -> Ordering,
    >(
        &self, phase: &mut H, order: F, camera: &Camera<P, W::NodePtr>,
        frame: &gfx::Frame<R>, renderer: &mut gfx::Renderer<R, C>)
        -> Result<(), Error>
    {
        // enqueue entities
        match phase.enqueue_all(self.entities.iter(), &self.world, camera,
                                self.cull_frustum) {
            Ok(()) => (),
            Err(e) => return Err(Error::Batch(e)),
        };
        // sort by custom criterias
        phase.sort_with(order);
        // flush into the renderer
        phase.flush(frame, renderer).map_err(|e| Error::Flush(e))
    }
}

/// A simple perspective camera based on the `World` trait.
pub type PerspectiveCam<W: World> = Camera<
    cgmath::PerspectiveFov<W::Scalar, cgmath::Rad<W::Scalar>>,
    W::NodePtr
>;
<commit_msg>Implemented Camera::get_view_projection()<commit_after>#![deny(missing_docs)]

//! Scene infrastructure to be used with Gfx phases.

extern crate gfx_phase;
extern crate gfx;
extern crate cgmath;

use std::cmp::Ordering;
use std::fmt::Debug;
use std::marker::PhantomData;

mod cull;
mod harness;

pub use self::cull::CullPhase;
pub use self::harness::PhaseHarness;

/// Scene drawing error.
#[derive(Debug)]
pub enum Error {
    /// Error in creating a batch.
    Batch(gfx::batch::Error),
    /// Error in sending a batch for drawing.
    Flush(gfx_phase::FlushError),
}

/// Abstract information about the view. Supposed to containt at least
/// Model-View-Projection transform for the shader.
pub trait ViewInfo<S, T: cgmath::Transform3<S>>: gfx_phase::ToDepth<Depth = S> {
    /// Construct a new information block.
    fn new(mvp: cgmath::Matrix4<S>, view: T, model: T) -> Self;
}

/// Abstract scene that can be drawn into something.
pub trait AbstractScene<R: gfx::Resources> {
    /// A type of the view information.
    type ViewInfo;
    /// A type of the entity.
    type Entity;
    /// A type of the camera.
    type Camera;

    /// Draw the contents of the scene with a specific phase into a renderer,
    /// using a given camera and a frame.
    fn draw<
        C: gfx::CommandBuffer<R>,
        H: gfx_phase::AbstractPhase<R, C, Self::Entity, Self::ViewInfo> + ?Sized,
    >(
        &self, &mut H, &Self::Camera, &gfx::Frame<R>, &mut gfx::Renderer<R, C>)
        -> Result<(), Error>;
}

/// An extension to `AbstractScene` that allows custom ordering of batches.
pub trait OrderedScene<R: gfx::Resources>: AbstractScene<R> {
    /// Draw the contents with a specific phase, given the ordering function.
    fn draw_ordered<
        C: gfx::CommandBuffer<R>,
        H: gfx_phase::AbstractPhase<R, C, Self::Entity, Self::ViewInfo> + ?Sized +
            gfx_phase::Ordered,
        F: Fn(&H::Object, &H::Object) -> Ordering,
    >(
        &self, &mut H, order: F, &Self::Camera, &gfx::Frame<R>, &mut gfx::Renderer<R, C>)
        -> Result<(), Error>;
}

/// A class that manages spatial relations between objects.
pub trait World {
    /// Type of the scalar used in all associated mathematical constructs.
    type Scalar: cgmath::BaseFloat + 'static;
    /// Type of the transform that every node performs relative to the parent.
    type Transform: cgmath::Transform3<Self::Scalar> + Clone;
    /// Pointer to a node, associated with an entity, camera, or something else.
    type NodePtr;
    /// Pointer to a skeleton, associated with an enttity.
    type SkeletonPtr;
    /// Get the transformation of a specific node pointer.
    fn get_transform(&self, &Self::NodePtr) -> Self::Transform;
}

/// A simple struct representing an object with a given material, mesh, bound,
/// and spatial relation to other stuff in the world.
pub struct Entity<R: gfx::Resources, M, W: World, B> {
    /// Name of the entity.
    pub name: String,
    /// Assotiated material of the entity.
    pub material: M,
    /// Mesh.
    pub mesh: gfx::Mesh<R>,
    /// Mesh slice.
    pub slice: gfx::Slice<R>,
    /// Node pointer into the world.
    pub node: W::NodePtr,
    /// Skeleton pointer.
    pub skeleton: Option<W::SkeletonPtr>,
    /// Associated spatial bound of the entity.
    pub bound: B,
}

impl<R: gfx::Resources, M: gfx_phase::Material, W: World, B> gfx_phase::Entity<R, M> for Entity<R, M, W, B> {
    fn get_material(&self) -> &M {
        &self.material
    }
    fn get_mesh(&self) -> (&gfx::Mesh<R>, &gfx::Slice<R>) {
        (&self.mesh, &self.slice)
    }
}

/// A simple camera with generic projection and spatial relation.
#[derive(Clone, Debug)]
pub struct Camera<P, N> {
    /// Name of the camera.
    pub name: String,
    /// Generic projection.
    pub projection: P,
    /// Generic spatial node.
    pub node: N,
}

impl<
    S: cgmath::BaseFloat + 'static,
    T: cgmath::ToMatrix4<S> + cgmath::Transform3<S> + Clone,
    W: World<Scalar = S, Transform = T>,
    P: cgmath::ToMatrix4<S>
> Camera<P, W::NodePtr> {
    /// Get the view-projection matrix, given the `World`.
    pub fn get_view_projection(&self, world: &W) -> cgmath::Matrix4<S> {
        use cgmath::{Matrix, Transform};
        let node_inverse = world.get_transform(&self.node).invert().unwrap();
        self.projection.to_matrix4().mul_m(&node_inverse.to_matrix4())
    }
}

/// An example scene type.
pub struct Scene<R: gfx::Resources, M, W: World, B, P, V> {
    /// A list of entities in the scene.
    pub entities: Vec<Entity<R, M, W, B>>,
    /// A list of cameras. It's not really useful, but `P` needs to be
    /// constrained in order to be able to implement `AbstractScene`.
    pub cameras: Vec<Camera<P, W::NodePtr>>,
    /// A flag controlling the frustum culling.
    pub cull_frustum: bool,
    /// Spatial world.
    pub world: W,
    _view_dummy: PhantomData<V>,
}

impl<R: gfx::Resources, M, W: World, B, P, V> Scene<R, M, W, B, P, V> {
    /// Create a new empty scene.
    pub fn new(world: W) -> Scene<R, M, W, B, P, V> {
        Scene {
            entities: Vec::new(),
            cameras: Vec::new(),
            cull_frustum: true,
            world: world,
            _view_dummy: PhantomData,
        }
    }
}

impl<
    R: gfx::Resources,
    M: gfx_phase::Material,
    W: World,
    B: cgmath::Bound<W::Scalar> + Debug,
    P: cgmath::Projection<W::Scalar>,
    V: ViewInfo<W::Scalar, W::Transform>,
> AbstractScene<R> for Scene<R, M, W, B, P, V> {
    type ViewInfo = V;
    type Entity = Entity<R, M, W, B>;
    type Camera = Camera<P, W::NodePtr>;

    fn draw<
        C: gfx::CommandBuffer<R>,
        H: gfx_phase::AbstractPhase<R, C, Entity<R, M, W, B>, V> + ?Sized,
    >(  &self, phase: &mut H, camera: &Camera<P, W::NodePtr>,
        frame: &gfx::Frame<R>, renderer: &mut gfx::Renderer<R, C>)
        -> Result<(), Error>
    {
        // enqueue entities
        match phase.enqueue_all(self.entities.iter(), &self.world, camera,
                                self.cull_frustum) {
            Ok(()) => (),
            Err(e) => return Err(Error::Batch(e)),
        };
        // sort by default criterias
        phase.sort();
        // flush into the renderer
        phase.flush(frame, renderer).map_err(|e| Error::Flush(e))
    }
}

impl<
    R: gfx::Resources,
    M: gfx_phase::Material,
    W: World,
    B: cgmath::Bound<W::Scalar> + Debug,
    P: cgmath::Projection<W::Scalar>,
    V: ViewInfo<W::Scalar, W::Transform>,
> OrderedScene<R> for Scene<R, M, W, B, P, V> {
    fn draw_ordered<
        C: gfx::CommandBuffer<R>,
        H: gfx_phase::AbstractPhase<R, C, Entity<R, M, W, B>, V> + ?Sized +
            gfx_phase::Ordered,
        F: Fn(&H::Object, &H::Object) -> Ordering,
    >(
        &self, phase: &mut H, order: F, camera: &Camera<P, W::NodePtr>,
        frame: &gfx::Frame<R>, renderer: &mut gfx::Renderer<R, C>)
        -> Result<(), Error>
    {
        // enqueue entities
        match phase.enqueue_all(self.entities.iter(), &self.world, camera,
                                self.cull_frustum) {
            Ok(()) => (),
            Err(e) => return Err(Error::Batch(e)),
        };
        // sort by custom criterias
        phase.sort_with(order);
        // flush into the renderer
        phase.flush(frame, renderer).map_err(|e| Error::Flush(e))
    }
}

/// A simple perspective camera based on the `World` trait.
pub type PerspectiveCam<W: World> = Camera<
    cgmath::PerspectiveFov<W::Scalar, cgmath::Rad<W::Scalar>>,
    W::NodePtr
>;
<|endoftext|>


<commit_before>mod camera;
mod filters;
mod image;
mod light;
mod material;
mod primitive;
mod renderer;

use std::error::Error;
use std::{io, fs, fmt};

use rustc_serialize::json::{self, Json};
use rustc_serialize::Decodable;

use geom::{Point, UnitVector};
use geom::shape::{Shape, Intersection, Mesh, Plane};
use geom::ray::{Ray};
use color::Color;
use self::camera::Camera ;
use self::light::Light;
use self::primitive::Primitive;
use self::material::Material;

pub use self::image::{Image, Pixel};
pub use self::filters::{NopFilter, SmoothingFilter};
pub use self::renderer::Renderer;

pub struct Scene {
    camera: Camera,
    ambient_light: Color,
    background_color: Color,
    primitives: Vec<Primitive>,
    lights: Vec<Light>,
}

#[derive(Debug)]
pub struct ParseError(String);

fn error(s: &str) -> ParseError {
    ParseError(s.to_string())
}

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

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl Scene {

    pub fn from_json(data: Json) -> Result<Scene, Box<Error>> {
        let conf = try!(data.find("camera").ok_or(error("wrong camera")));
        let camera = try!(read_camera(conf));
        let ambient_light = try!(data.find("ambient_light").and_then(read::<Color>)
                                 .ok_or(error("wrong ambient")));
        let background_color = try!(data.find("background").and_then(read::<Color>)
                                    .ok_or(error("wrong background")));

        let ps = try!(data.find("primitives")
                     .and_then(Json::as_array)
                     .ok_or(error("wrong primitives")));

        let primitives = try!(ps.iter().map(read_primitive)
                              .collect::<Result<Vec<Primitive>, _>>());

        let ls = try!(data.find("lights")
                      .and_then(Json::as_array)
                      .ok_or(error("wrong lights")));

        let lights = try!(ls.iter().map(read_light)
                          .collect::<Result<Vec<_>, _>>());

        Ok(Scene {
            camera: camera,
            ambient_light: ambient_light,
            background_color: background_color,
            primitives: primitives,
            lights: lights,
        })
    }

    fn find_obstacle(&self, ray: &Ray) -> Option<(&Primitive, Intersection)> {
        let mut result = None;
        for obj in self.primitives.iter() {
            if let Some(intersection) = obj.shape.intersect(&ray) {
                result = match result {
                    None => Some((obj, intersection)),
                    Some(previous) if intersection < previous.1 => Some((obj, intersection)),
                    _ => result
                }
            }
        }
        result
    }

    fn is_visible(&self, what: Point, from: Point) -> bool {
        let ray = Ray::from_to(from, what);
        let ray = Ray::from_to(ray.along(1e-6) , what);
        // FIXME: what if obstacle is behind a light source?
        self.find_obstacle(&ray).is_none()
    }
}

fn read<T: Decodable>(data: &Json) -> Option<T> {
    json::decode(&data.to_string()).ok()
}

fn read_camera(data: &Json) -> Result<Camera, Box<Error>> {
    let config = try!(json::decode(&data.to_string()));
    Ok(Camera::new(config))
}

fn read_primitive(data: &Json) -> Result<Primitive, Box<Error>> {
    let t = try!(data.find("type")
                 .and_then(Json::as_string)
                 .ok_or(error("bad primitive")));
    if t == "mesh" {
        let location = try!(data.find("location").and_then(Json::as_string)
                            .ok_or(error("bad primitive")));
        let color = try!(data.find("color").and_then(read::<Color>)
                         .ok_or(error("bad primitive")));

        let mut file = try!(fs::File::open(&location).map(io::BufReader::new));
        let mesh = try!(Mesh::from_obj(&mut file));

        Ok(Primitive::new(mesh, Material {color: color, diffuse: 0.9, specular: 4.0}))
    } else if t == "plane" {
        let position = try!(data.find("position").and_then(read::<Point>)
                           .ok_or(error("bad primitive")));
        let normal = try!(data.find("normal").and_then(read::<UnitVector>)
                          .ok_or(error("bad primitive")));
        let color = try!(data.find("color").and_then(read::<Color>)
                         .ok_or(error("bad primitive")));

        Ok(Primitive::new(Plane::new(position, normal),
                          Material {color: color, diffuse: 0.9, specular: 4.0}))
    } else {
        Err(Box::new(error("bad primitive")))
    }
}

fn read_light(data: &Json) -> Result<Light, Box<Error>> {
    let light = try!(json::decode(&data.to_string()));
    Ok(light)
}
<commit_msg>remove dulication<commit_after>mod camera;
mod filters;
mod image;
mod light;
mod material;
mod primitive;
mod renderer;

use std::error::Error;
use std::{io, fs, fmt};

use rustc_serialize::json::{self, Json};
use rustc_serialize::Decodable ;

use geom::{Point, UnitVector};
use geom::shape::{Shape, Intersection, Mesh, Plane};
use geom::ray::{Ray};
use color::Color;
use self::camera::Camera ;
use self::light::Light;
use self::primitive::Primitive;
use self::material::Material;

pub use self::image::{Image, Pixel};
pub use self::filters::{NopFilter, SmoothingFilter};
pub use self::renderer::Renderer;

pub struct Scene {
    camera: Camera,
    ambient_light: Color,
    background_color: Color,
    primitives: Vec<Primitive>,
    lights: Vec<Light>,
}

#[derive(Debug)]
pub struct ParseError(String);

fn error(s: &str) -> Box<Error> {
    Box::new(ParseError(s.to_string()))
}

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

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl Scene {

    pub fn from_json(data: Json) -> Result<Scene, Box<Error>> {
        let conf = try!(data.find("camera").ok_or(error("wrong camera")));
        let camera = try!(read_camera(conf));
        let ambient_light = try!(data.find("ambient_light").ok_or(error("wrong ambient"))
                                 .and_then(read::<Color>));
        let background_color = try!(data.find("background").ok_or(error("wrong background"))
                                    .and_then(read::<Color>));

        let ps = try!(data.find("primitives")
                     .and_then(Json::as_array)
                     .ok_or(error("wrong primitives")));

        let primitives = try!(ps.iter().map(read_primitive)
                              .collect::<Result<Vec<Primitive>, _>>());

        let ls = try!(data.find("lights")
                      .and_then(Json::as_array)
                      .ok_or(error("wrong lights")));

        let lights = try!(ls.iter().map(read::<Light>)
                          .collect::<Result<Vec<_>, _>>());

        Ok(Scene {
            camera: camera,
            ambient_light: ambient_light,
            background_color: background_color,
            primitives: primitives,
            lights: lights,
        })
    }

    fn find_obstacle(&self, ray: &Ray) -> Option<(&Primitive, Intersection)> {
        let mut result = None;
        for obj in self.primitives.iter() {
            if let Some(intersection) = obj.shape.intersect(&ray) {
                result = match result {
                    None => Some((obj, intersection)),
                    Some(previous) if intersection < previous.1 => Some((obj, intersection)),
                    _ => result
                }
            }
        }
        result
    }

    fn is_visible(&self, what: Point, from: Point) -> bool {
        let ray = Ray::from_to(from, what);
        let ray = Ray::from_to(ray.along(1e-6) , what);
        // FIXME: what if obstacle is behind a light source?
        self.find_obstacle(&ray).is_none()
    }
}

fn read<T: Decodable>(data: &Json) -> Result<T, Box<Error>> {
    let mut decoder = json::Decoder::new(data.clone());
    let result = try!(Decodable::decode(&mut decoder));
    Ok(result)
}

fn read_camera(data: &Json) -> Result<Camera, Box<Error>> {
    let config = try!(json::decode(&data.to_string()));
    Ok(Camera::new(config))
}

fn read_primitive(data: &Json) -> Result<Primitive, Box<Error>> {
    let t = try!(data.find("type")
                 .and_then(Json::as_string)
                 .ok_or(error("bad primitive")));
    if t == "mesh" {
        let location = try!(data.find("location").and_then(Json::as_string)
                            .ok_or(error("bad primitive")));
        let color = try!(data.find("color").ok_or(error("bad primitive"))
                         .and_then(read::<Color>));

        let mut file = try!(fs::File::open(&location).map(io::BufReader::new));
        let mesh = try!(Mesh::from_obj(&mut file));

        Ok(Primitive::new(mesh, Material {color: color, diffuse: 0.9, specular: 4.0}))
    } else if t == "plane" {
        let position = try!(data.find("position").ok_or(error("bad primitive"))
                           .and_then(read::<Point>));
        let normal = try!(data.find("normal").ok_or(error("bad primitive"))
                          .and_then(read::<UnitVector>));
        let color = try!(data.find("color").ok_or(error("bad primitive"))
                         .and_then(read::<Color>));

        Ok(Primitive::new(Plane::new(position, normal),
                          Material {color: color, diffuse: 0.9, specular: 4.0}))
    } else {
        Err(error("bad primitive"))
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_imports)]
use super::*;
use std::env;

const ENV_KEY: &str = "PROXER_API_KEY";

#[test]
fn api_response()
{
	// is the api structured as we want it to be?
	info!("creating client");
	let client = Client::with_env_key(ENV_KEY)
		.expect("can't read api-key from environment");

	info!("build request");
	let req = client
		.api()
		.info()
		.get_fullentry(parameter::InfoGetFullEntry { id: 53 });

	info!("send request");
	let res = client.execute(req);
	info!("request sent");

	match res
	{
		Err(e) => {
			error!("error...");
			eprintln!("response {:#?}", e);

			match e
			{
				error::Error::Api(e) => {
					info!("api error");

					match e.error()
					{
						error::api::Errcode::NoApiPermissions => return,
						_ => panic!("unexpected api error: {}", e),
					}
				}
				error::Error::Json(e) => panic!("can't parse json: {}", e),
				error::Error::Unknown => panic!("unknown error"),
				_ => return,
			}
		}

		Ok(r) => {
			info!("Ok");
			assert_eq!(r.medium, "animeseries");
		}
	}
}
<commit_msg>make test pass<commit_after>#![allow(dead_code, unused_imports)]
use super::*;
use std::env;

const ENV_KEY: &str = "PROXER_API_KEY";

#[test]
fn api_response()
{
	// is the api structured as we want it to be?
	info!("creating client");
	let client = Client::with_env_key(ENV_KEY)
		.expect("can't read api-key from environment");

	info!("build request");
	let req = api::info::GetFullEntry::new(
		parameter::InfoGetFullEntry { id: 53 }
	);

	info!("send request");
	let res = client.execute(req);
	info!("request sent");

	match res
	{
		Err(e) => {
			error!("error...");
			eprintln!("response {:#?}", e);

			match e
			{
				error::Error::Api(e) => {
					info!("api error");

					match e.error()
					{
						error::api::Errcode::NoApiPermissions => return,
						_ => panic!("unexpected api error: {}", e),
					}
				}
				error::Error::Json(e) => panic!("can't parse json: {}", e),
				error::Error::Unknown => panic!("unknown error"),
				_ => return,
			}
		}

		Ok(r) => {
			info!("Ok");
			assert_eq!(r.medium, "animeseries");
		}
	}
}
<|endoftext|>


<commit_before>use num::{FromPrimitive, ToPrimitive};

use byteorder::{ByteOrder, LittleEndian};
use failure::{Error, Fail};
use zydis::gen::*;
use zydis::Decoder;

use super::analysis::Analysis;
use super::arch::Arch;
use super::loader;
use super::loader::{LoadedModule, Loader};
use super::util;

#[derive(Debug, Fail)]
pub enum WorkspaceError {
    #[fail(display = "The given buffer is not supported (arch/plat/file format)")]
    NotSupported,
    #[fail(display = "The given address is not mapped")]
    InvalidAddress,
    #[fail(display = "Buffer overrun")]
    BufferOverrun,
    #[fail(display = "The instruction at the given address is invalid")]
    InvalidInstruction,
}

pub struct WorkspaceBuilder<A: Arch> {
    filename: String,
    buf: Vec<u8>,

    loader: Option<Box<dyn Loader<A>>>,
}

impl<A: Arch + 'static + std::fmt::Debug> WorkspaceBuilder<A> {
    /// Override the default loader picker with the given loader.
    pub fn with_loader(
        self: WorkspaceBuilder<A>,
        loader: Box<dyn Loader<A>>,
    ) -> WorkspaceBuilder<A> {
        WorkspaceBuilder {
            loader: Some(loader),
            ..self
        }
    }

    /// Construct a workspace with the given builder configuration.
    ///
    /// This invokes the loaders, analyzers, and another other logic,
    ///  resulting in an initialized Workspace instance.
    ///
    /// Example (with default loader):
    ///
    /// ```
    /// use lancelot::arch::*;
    /// use lancelot::workspace::Workspace;
    ///
    /// Workspace::<Arch32>::from_bytes("foo.bin", b"\xEB\xFE")
    ///   .load()
    ///   .map(|ws| {
    ///     assert_eq!(ws.loader.get_name(),       "Windows/32/Raw");
    ///     assert_eq!(ws.module.base_address,     0x0);
    ///     assert_eq!(ws.module.sections[0].name, "raw");
    ///   })
    ///   .map_err(|e| panic!(e));
    /// ```
    ///
    /// Example (with specific loader):
    ///
    /// ```
    /// use lancelot::arch::*;
    /// use lancelot::loader::Platform;
    /// use lancelot::workspace::Workspace;
    /// use lancelot::loaders::sc::ShellcodeLoader;
    ///
    /// Workspace::<Arch32>::from_bytes("foo.bin", b"\xEB\xFE")
    ///   .with_loader(Box::new(ShellcodeLoader::<Arch32>::new(Platform::Windows)))
    ///   .load()
    ///   .map(|ws| {
    ///     assert_eq!(ws.loader.get_name(),       "Windows/32/Raw");
    ///     assert_eq!(ws.module.base_address,     0x0);
    ///     assert_eq!(ws.module.sections[0].name, "raw");
    ///   })
    ///   .map_err(|e| panic!(e));
    /// ```
    pub fn load(self: WorkspaceBuilder<A>) -> Result<Workspace<A>, Error> {
        // if the user provided a loader, use that.
        // otherwise, use the default detected loader.
        let (ldr, module) = match self.loader {
            Some(ldr) => {
                let module = ldr.load(&self.buf)?;
                (ldr, module)
            }
            None => loader::load::<A>(&self.buf)?,
        };

        let analysis = Analysis::new(&module);

        let decoder = if A::get_bits() == 32 {
            Decoder::new(ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_ADDRESS_WIDTH_32).unwrap()
        } else {
            Decoder::new(ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64).unwrap()
        };

        Ok(Workspace::<A> {
            filename: self.filename,
            buf: self.buf,

            loader: ldr,
            module,

            decoder,

            analysis,
        })
    }
}

pub struct Workspace<A: Arch> {
    // name or source of the file
    pub filename: String,
    // raw bytes of the file
    pub buf: Vec<u8>,

    pub loader: Box<dyn Loader<A>>,
    pub module: LoadedModule<A>,

    pub decoder: Decoder,

    // pub only so that we can split the impl
    pub analysis: Analysis<A>,
}

impl<A: Arch + 'static> Workspace<A> {
    /// Create a workspace and load the given bytes.
    ///
    /// See example on `WorkspaceBuilder::load()`
    pub fn from_bytes(filename: &str, buf: &[u8]) -> WorkspaceBuilder<A> {
        WorkspaceBuilder {
            filename: filename.to_string(),
            buf: buf.to_vec(),
            loader: None,
        }
    }

    pub fn from_file(filename: &str) -> Result<WorkspaceBuilder<A>, Error> {
        Ok(WorkspaceBuilder {
            filename: filename.to_string(),
            buf: util::read_file(filename)?,
            loader: None,
        })
    }

    /// Read bytes from the given RVA.
    ///
    /// Errors:
    ///
    ///   - InvalidAddress - if the address is not mapped.
    ///   - BufferOverrun - if the requested region runs beyond the matching section.
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\xEB\xFE");
    /// assert_eq!(ws.read_bytes(0x0, 0x1).unwrap().to_vec(), b"\xEB");
    /// assert_eq!(ws.read_bytes(0x1, 0x1).unwrap().to_vec(), b"\xFE");
    /// assert_eq!(ws.read_bytes(0x0, 0x2).unwrap().to_vec(), b"\xEB\xFE");
    /// assert_eq!(ws.read_bytes(0x0, 0x3).is_err(), true);
    /// assert_eq!(ws.read_bytes(0x2, 0x1).is_err(), true);
    /// ```
    pub fn read_bytes(&self, rva: A::RVA, length: usize) -> Result<&[u8], Error> {
        self.module
            .sections
            .iter()
            .filter(|section| section.contains(rva))
            .nth(0)
            .ok_or_else(|| WorkspaceError::InvalidAddress.into())
            .and_then(|section| -> Result<&[u8], Error> {
                // rva is guaranteed to be within this section,
                // so we can do an unchecked subtract here.
                let offset = rva - section.addr;
                A::RVA::to_usize(&offset)
                    .ok_or_else(|| WorkspaceError::InvalidAddress.into())
                    .and_then(|offset| {
                        if offset + length > section.buf.len() {
                            Err(WorkspaceError::BufferOverrun.into())
                        } else {
                            Ok(&section.buf[offset..offset + length])
                        }
                    })
            })
    }

    /// Is the given range mapped?
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\xEB\xFE");
    /// assert!( ws.probe(0x0, 1));
    /// assert!( ws.probe(0x0, 2));
    /// assert!(!ws.probe(0x0, 3));
    /// assert!( ws.probe(0x1, 1));
    /// assert!(!ws.probe(0x2, 1));
    /// ```
    pub fn probe(&self, rva: A::RVA, length: usize) -> bool {
        self.read_bytes(rva, length).is_ok()
    }

    /// Read a byte from the given RVA.
    ///
    /// Errors: same as `read_bytes`.
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\xEB\xFE");
    /// assert_eq!(ws.read_u8(0x0).unwrap(), 0xEB);
    /// assert_eq!(ws.read_u8(0x1).unwrap(), 0xFE);
    /// assert_eq!(ws.read_u8(0x2).is_err(), true);
    /// ```
    pub fn read_u8(&self, rva: A::RVA) -> Result<u8, Error> {
        self.read_bytes(rva, 1).and_then(|buf| Ok(buf[0]))
    }

    /// Read a word from the given RVA.
    ///
    /// Errors: same as `read_bytes`.
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\xEB\xFE");
    /// assert_eq!(ws.read_u16(0x0).unwrap(), 0xFEEB);
    /// assert_eq!(ws.read_u16(0x1).is_err(), true);
    /// assert_eq!(ws.read_u16(0x2).is_err(), true);
    /// ```
    pub fn read_u16(&self, rva: A::RVA) -> Result<u16, Error> {
        self.read_bytes(rva, 2)
            .and_then(|buf| Ok(LittleEndian::read_u16(buf)))
    }

    /// Read a dword from the given RVA.
    pub fn read_u32(&self, rva: A::RVA) -> Result<u32, Error> {
        self.read_bytes(rva, 4)
            .and_then(|buf| Ok(LittleEndian::read_u32(buf)))
    }

    /// Read a qword from the given RVA.
    pub fn read_u64(&self, rva: A::RVA) -> Result<u64, Error> {
        self.read_bytes(rva, 8)
            .and_then(|buf| Ok(LittleEndian::read_u64(buf)))
    }

    /// Read an RVA from the given RVA.
    /// Note that the size of the read is dependent on the architecture.
    ///
    /// Errors: same as `read_bytes`.
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\x00\x11\x22\x33");
    /// assert_eq!(ws.read_rva(0x0).unwrap(), 0x33221100);
    /// assert_eq!(ws.read_rva(0x1).is_err(), true);
    /// ```
    pub fn read_rva(&self, rva: A::RVA) -> Result<A::RVA, Error> {
        match A::get_bits() {
            // these conversions will never fail
            32 => Ok(A::RVA::from_u32(self.read_u32(rva)?).unwrap()),
            64 => Ok(A::RVA::from_u64(self.read_u64(rva)?).unwrap()),
            _ => panic!("unexpected architecture"),
        }
    }

    /// Read a VA from the given RVA.
    /// Note that the size of the read is dependent on the architecture.
    pub fn read_va(&self, rva: A::RVA) -> Result<A::VA, Error> {
        match A::get_bits() {
            // these conversions will never fail
            32 => Ok(A::VA::from_u32(self.read_u32(rva)?).unwrap()),
            64 => Ok(A::VA::from_u64(self.read_u64(rva)?).unwrap()),
            _ => panic!("unexpected architecture"),
        }
    }

    /// Decode an instruction at the given RVA.
    ///
    /// Errors:
    ///
    ///   - InvalidAddress - if the address is not mapped.
    ///   - BufferOverrun - if the requested region runs beyond the matching section.
    ///   - InvalidInstruction - if an instruction cannot be decoded.
    ///
    /// Example:
    ///
    /// ```
    /// use zydis::gen::*;
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\xEB\xFE");
    /// assert_eq!(ws.read_insn(0x0).is_ok(), true);
    /// assert_eq!(ws.read_insn(0x0).unwrap().length, 2);
    /// assert_eq!(ws.read_insn(0x0).unwrap().mnemonic as i32, ZYDIS_MNEMONIC_JMP);
    /// ```
    pub fn read_insn(&self, rva: A::RVA) -> Result<ZydisDecodedInstruction, Error> {
        // this is `read_bytes` except that it reads at most 0x10 bytes.
        // if less are available, then less are returned.
        let buf = self
            .module
            .sections
            .iter()
            .filter(|section| section.contains(rva))
            .nth(0)
            .ok_or_else(|| WorkspaceError::InvalidAddress.into())
            .and_then(|section| -> Result<&[u8], Error> {
                // rva is guaranteed to be within this section,
                // so we can do an unchecked subtract here.
                let offset = rva - section.addr;
                A::RVA::to_usize(&offset)
                    .ok_or_else(|| WorkspaceError::InvalidAddress.into())
                    .and_then(|offset| {
                        if offset + 0x10 > section.buf.len() {
                            Ok(&section.buf[offset..])
                        } else {
                            Ok(&section.buf[offset..offset + 0x10])
                        }
                    })
            })?;

        // RVA will always be either u32 or u64 (never bigger),
        // so we can always fit this into a u64.
        let pc = A::RVA::to_u64(&rva).unwrap();

        match self.decoder.decode(&buf, pc) {
            Ok(Some(insn)) => Ok(insn),
            Ok(None) => Err(WorkspaceError::InvalidInstruction.into()),
            Err(_) => Err(WorkspaceError::InvalidInstruction.into()),
        }
    }

    // API:
    //   get_insn
    //   get_xrefs_to
    //   get_xrefs_from
    //   get_functions

    // elsewhere:
    //   call graph
    //   control flow graph

    // see: `analysis::impl Workspace`
}
<commit_msg>workspace: debug loading results<commit_after>use num::{FromPrimitive, ToPrimitive};

use byteorder::{ByteOrder, LittleEndian};
use failure::{Error, Fail};
use zydis::gen::*;
use zydis::Decoder;
use log::{debug, info, warn};

use super::analysis::Analysis;
use super::arch::Arch;
use super::loader;
use super::loader::{LoadedModule, Loader};
use super::util;

#[derive(Debug, Fail)]
pub enum WorkspaceError {
    #[fail(display = "The given buffer is not supported (arch/plat/file format)")]
    NotSupported,
    #[fail(display = "The given address is not mapped")]
    InvalidAddress,
    #[fail(display = "Buffer overrun")]
    BufferOverrun,
    #[fail(display = "The instruction at the given address is invalid")]
    InvalidInstruction,
}

pub struct WorkspaceBuilder<A: Arch> {
    filename: String,
    buf: Vec<u8>,

    loader: Option<Box<dyn Loader<A>>>,
}

impl<A: Arch + 'static + std::fmt::Debug> WorkspaceBuilder<A> {
    /// Override the default loader picker with the given loader.
    pub fn with_loader(
        self: WorkspaceBuilder<A>,
        loader: Box<dyn Loader<A>>,
    ) -> WorkspaceBuilder<A> {
        info!("using explicitly chosen loader: {}", loader.get_name());
        WorkspaceBuilder {
            loader: Some(loader),
            ..self
        }
    }

    /// Construct a workspace with the given builder configuration.
    ///
    /// This invokes the loaders, analyzers, and another other logic,
    ///  resulting in an initialized Workspace instance.
    ///
    /// Example (with default loader):
    ///
    /// ```
    /// use lancelot::arch::*;
    /// use lancelot::workspace::Workspace;
    ///
    /// Workspace::<Arch32>::from_bytes("foo.bin", b"\xEB\xFE")
    ///   .load()
    ///   .map(|ws| {
    ///     assert_eq!(ws.loader.get_name(),       "Windows/32/Raw");
    ///     assert_eq!(ws.module.base_address,     0x0);
    ///     assert_eq!(ws.module.sections[0].name, "raw");
    ///   })
    ///   .map_err(|e| panic!(e));
    /// ```
    ///
    /// Example (with specific loader):
    ///
    /// ```
    /// use lancelot::arch::*;
    /// use lancelot::loader::Platform;
    /// use lancelot::workspace::Workspace;
    /// use lancelot::loaders::sc::ShellcodeLoader;
    ///
    /// Workspace::<Arch32>::from_bytes("foo.bin", b"\xEB\xFE")
    ///   .with_loader(Box::new(ShellcodeLoader::<Arch32>::new(Platform::Windows)))
    ///   .load()
    ///   .map(|ws| {
    ///     assert_eq!(ws.loader.get_name(),       "Windows/32/Raw");
    ///     assert_eq!(ws.module.base_address,     0x0);
    ///     assert_eq!(ws.module.sections[0].name, "raw");
    ///   })
    ///   .map_err(|e| panic!(e));
    /// ```
    pub fn load(self: WorkspaceBuilder<A>) -> Result<Workspace<A>, Error> {
        // if the user provided a loader, use that.
        // otherwise, use the default detected loader.
        let (ldr, module) = match self.loader {
            Some(ldr) => {
                let module = ldr.load(&self.buf)?;
                (ldr, module)
            }
            None => loader::load::<A>(&self.buf)?,
        };

        info!("loaded {} sections:", module.sections.len());
        module.sections.iter().for_each(|sec| {
            info!("  - {:8} {:>8x}", sec.name, sec.addr);
        });

        let analysis = Analysis::new(&module);

        let decoder = if A::get_bits() == 32 {
            Decoder::new(ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_ADDRESS_WIDTH_32).unwrap()
        } else {
            Decoder::new(ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64).unwrap()
        };

        Ok(Workspace::<A> {
            filename: self.filename,
            buf: self.buf,

            loader: ldr,
            module,

            decoder,

            analysis,
        })
    }
}

pub struct Workspace<A: Arch> {
    // name or source of the file
    pub filename: String,
    // raw bytes of the file
    pub buf: Vec<u8>,

    pub loader: Box<dyn Loader<A>>,
    pub module: LoadedModule<A>,

    pub decoder: Decoder,

    // pub only so that we can split the impl
    pub analysis: Analysis<A>,
}

impl<A: Arch + 'static> Workspace<A> {
    /// Create a workspace and load the given bytes.
    ///
    /// See example on `WorkspaceBuilder::load()`
    pub fn from_bytes(filename: &str, buf: &[u8]) -> WorkspaceBuilder<A> {
        WorkspaceBuilder {
            filename: filename.to_string(),
            buf: buf.to_vec(),
            loader: None,
        }
    }

    pub fn from_file(filename: &str) -> Result<WorkspaceBuilder<A>, Error> {
        Ok(WorkspaceBuilder {
            filename: filename.to_string(),
            buf: util::read_file(filename)?,
            loader: None,
        })
    }

    /// Read bytes from the given RVA.
    ///
    /// Errors:
    ///
    ///   - InvalidAddress - if the address is not mapped.
    ///   - BufferOverrun - if the requested region runs beyond the matching section.
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\xEB\xFE");
    /// assert_eq!(ws.read_bytes(0x0, 0x1).unwrap().to_vec(), b"\xEB");
    /// assert_eq!(ws.read_bytes(0x1, 0x1).unwrap().to_vec(), b"\xFE");
    /// assert_eq!(ws.read_bytes(0x0, 0x2).unwrap().to_vec(), b"\xEB\xFE");
    /// assert_eq!(ws.read_bytes(0x0, 0x3).is_err(), true);
    /// assert_eq!(ws.read_bytes(0x2, 0x1).is_err(), true);
    /// ```
    pub fn read_bytes(&self, rva: A::RVA, length: usize) -> Result<&[u8], Error> {
        self.module
            .sections
            .iter()
            .filter(|section| section.contains(rva))
            .nth(0)
            .ok_or_else(|| WorkspaceError::InvalidAddress.into())
            .and_then(|section| -> Result<&[u8], Error> {
                // rva is guaranteed to be within this section,
                // so we can do an unchecked subtract here.
                let offset = rva - section.addr;
                A::RVA::to_usize(&offset)
                    .ok_or_else(|| WorkspaceError::InvalidAddress.into())
                    .and_then(|offset| {
                        if offset + length > section.buf.len() {
                            Err(WorkspaceError::BufferOverrun.into())
                        } else {
                            Ok(&section.buf[offset..offset + length])
                        }
                    })
            })
    }

    /// Is the given range mapped?
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\xEB\xFE");
    /// assert!( ws.probe(0x0, 1));
    /// assert!( ws.probe(0x0, 2));
    /// assert!(!ws.probe(0x0, 3));
    /// assert!( ws.probe(0x1, 1));
    /// assert!(!ws.probe(0x2, 1));
    /// ```
    pub fn probe(&self, rva: A::RVA, length: usize) -> bool {
        self.read_bytes(rva, length).is_ok()
    }

    /// Read a byte from the given RVA.
    ///
    /// Errors: same as `read_bytes`.
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\xEB\xFE");
    /// assert_eq!(ws.read_u8(0x0).unwrap(), 0xEB);
    /// assert_eq!(ws.read_u8(0x1).unwrap(), 0xFE);
    /// assert_eq!(ws.read_u8(0x2).is_err(), true);
    /// ```
    pub fn read_u8(&self, rva: A::RVA) -> Result<u8, Error> {
        self.read_bytes(rva, 1).and_then(|buf| Ok(buf[0]))
    }

    /// Read a word from the given RVA.
    ///
    /// Errors: same as `read_bytes`.
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\xEB\xFE");
    /// assert_eq!(ws.read_u16(0x0).unwrap(), 0xFEEB);
    /// assert_eq!(ws.read_u16(0x1).is_err(), true);
    /// assert_eq!(ws.read_u16(0x2).is_err(), true);
    /// ```
    pub fn read_u16(&self, rva: A::RVA) -> Result<u16, Error> {
        self.read_bytes(rva, 2)
            .and_then(|buf| Ok(LittleEndian::read_u16(buf)))
    }

    /// Read a dword from the given RVA.
    pub fn read_u32(&self, rva: A::RVA) -> Result<u32, Error> {
        self.read_bytes(rva, 4)
            .and_then(|buf| Ok(LittleEndian::read_u32(buf)))
    }

    /// Read a qword from the given RVA.
    pub fn read_u64(&self, rva: A::RVA) -> Result<u64, Error> {
        self.read_bytes(rva, 8)
            .and_then(|buf| Ok(LittleEndian::read_u64(buf)))
    }

    /// Read an RVA from the given RVA.
    /// Note that the size of the read is dependent on the architecture.
    ///
    /// Errors: same as `read_bytes`.
    ///
    /// Example:
    ///
    /// ```
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\x00\x11\x22\x33");
    /// assert_eq!(ws.read_rva(0x0).unwrap(), 0x33221100);
    /// assert_eq!(ws.read_rva(0x1).is_err(), true);
    /// ```
    pub fn read_rva(&self, rva: A::RVA) -> Result<A::RVA, Error> {
        match A::get_bits() {
            // these conversions will never fail
            32 => Ok(A::RVA::from_u32(self.read_u32(rva)?).unwrap()),
            64 => Ok(A::RVA::from_u64(self.read_u64(rva)?).unwrap()),
            _ => panic!("unexpected architecture"),
        }
    }

    /// Read a VA from the given RVA.
    /// Note that the size of the read is dependent on the architecture.
    pub fn read_va(&self, rva: A::RVA) -> Result<A::VA, Error> {
        match A::get_bits() {
            // these conversions will never fail
            32 => Ok(A::VA::from_u32(self.read_u32(rva)?).unwrap()),
            64 => Ok(A::VA::from_u64(self.read_u64(rva)?).unwrap()),
            _ => panic!("unexpected architecture"),
        }
    }

    /// Decode an instruction at the given RVA.
    ///
    /// Errors:
    ///
    ///   - InvalidAddress - if the address is not mapped.
    ///   - BufferOverrun - if the requested region runs beyond the matching section.
    ///   - InvalidInstruction - if an instruction cannot be decoded.
    ///
    /// Example:
    ///
    /// ```
    /// use zydis::gen::*;
    /// use lancelot::test;
    ///
    /// let ws = test::get_shellcode32_workspace(b"\xEB\xFE");
    /// assert_eq!(ws.read_insn(0x0).is_ok(), true);
    /// assert_eq!(ws.read_insn(0x0).unwrap().length, 2);
    /// assert_eq!(ws.read_insn(0x0).unwrap().mnemonic as i32, ZYDIS_MNEMONIC_JMP);
    /// ```
    pub fn read_insn(&self, rva: A::RVA) -> Result<ZydisDecodedInstruction, Error> {
        // this is `read_bytes` except that it reads at most 0x10 bytes.
        // if less are available, then less are returned.
        let buf = self
            .module
            .sections
            .iter()
            .filter(|section| section.contains(rva))
            .nth(0)
            .ok_or_else(|| WorkspaceError::InvalidAddress.into())
            .and_then(|section| -> Result<&[u8], Error> {
                // rva is guaranteed to be within this section,
                // so we can do an unchecked subtract here.
                let offset = rva - section.addr;
                A::RVA::to_usize(&offset)
                    .ok_or_else(|| WorkspaceError::InvalidAddress.into())
                    .and_then(|offset| {
                        if offset + 0x10 > section.buf.len() {
                            Ok(&section.buf[offset..])
                        } else {
                            Ok(&section.buf[offset..offset + 0x10])
                        }
                    })
            })?;

        // RVA will always be either u32 or u64 (never bigger),
        // so we can always fit this into a u64.
        let pc = A::RVA::to_u64(&rva).unwrap();

        match self.decoder.decode(&buf, pc) {
            Ok(Some(insn)) => Ok(insn),
            Ok(None) => Err(WorkspaceError::InvalidInstruction.into()),
            Err(_) => Err(WorkspaceError::InvalidInstruction.into()),
        }
    }

    // API:
    //   get_insn
    //   get_xrefs_to
    //   get_xrefs_from
    //   get_functions

    // elsewhere:
    //   call graph
    //   control flow graph

    // see: `analysis::impl Workspace`
}
<|endoftext|>