<commit_before>use std::collections::{HashMap, VecDeque};

use serde::Serialize;
use serde_json::value::{to_value, Map, Value as Json};

use crate::block::{BlockContext, BlockParamHolder};
use crate::error::RenderError;
use crate::grammar::Rule;
use crate::json::path::*;
use crate::json::value::ScopedJson;
use crate::util::extend;

pub type Object = HashMap<String, Json>;

/// The context wrap data you render on your templates.
///
#[derive(Debug, Clone)]
pub struct Context {
    data: Json,
}

#[derive(Debug)]
enum ResolvedPath<'a> {
    // FIXME: change to borrowed when possible
    // full path
    AbsolutePath(Vec<String>),
    // relative path and path root
    RelativePath(Vec<String>),
    // relative path against block param value
    BlockParamValue(Vec<String>, &'a Json),
}

fn parse_json_visitor<'a>(
    relative_path: &[PathSeg],
    block_contexts: &'a VecDeque<BlockContext>,
    always_for_absolute_path: bool,
) -> Result<ResolvedPath<'a>, RenderError> {
    let mut path_context_depth: i64 = 0;
    let mut with_block_param = None;
    let mut from_root = false;

    // peek relative_path for block param, @root and  "../../"
    for path_seg in relative_path {
        match path_seg {
            PathSeg::Named(the_path) => {
                if let Some(holder) = get_in_block_params(&block_contexts, the_path) {
                    with_block_param = Some(holder);
                }
                break;
            }
            PathSeg::Ruled(the_rule) => match the_rule {
                Rule::path_root => {
                    from_root = true;
                    break;
                }
                Rule::path_up => path_context_depth += 1,
                _ => break,
            },
        }
    }

    let mut path_stack = Vec::with_capacity(relative_path.len() + 5);
    match with_block_param {
        Some(BlockParamHolder::Value(ref value)) => {
            merge_json_path(&mut path_stack, &relative_path[1..]);
            Ok(ResolvedPath::BlockParamValue(path_stack, value))
        }
        Some(BlockParamHolder::Path(ref paths)) => {
            // TODO: if this path equals base_path, skip this step and make it a ResolvedPath::RelativePath
            if let Some(ref base_path) = block_contexts.front().map(|blk| blk.base_path()) {
                extend(&mut path_stack, base_path);
            }
            if !paths.is_empty() {
                extend(&mut path_stack, paths);
            }
            merge_json_path(&mut path_stack, &relative_path[1..]);

            Ok(ResolvedPath::AbsolutePath(path_stack))
        }
        None => {
            if path_context_depth > 0 {
                if let Some(ref context_base_path) = block_contexts
                    .get(path_context_depth as usize)
                    .map(|blk| blk.base_path())
                {
                    extend(&mut path_stack, context_base_path);
                } else {
                    // TODO: is this correct behaviour?
                    if let Some(ref base_path) = block_contexts.front().map(|blk| blk.base_path()) {
                        extend(&mut path_stack, base_path);
                    }
                }
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else if from_root {
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else if always_for_absolute_path {
                if let Some(base_path) = block_contexts.front().map(|blk| blk.base_path()) {
                    extend(&mut path_stack, base_path);
                }
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else {
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::RelativePath(path_stack))
            }
        }
    }
}

fn get_data<'a>(d: Option<&'a Json>, p: &str) -> Result<Option<&'a Json>, RenderError> {
    let result = match d {
        Some(&Json::Array(ref l)) => p
            .parse::<usize>()
            .map_err(RenderError::with)
            .map(|idx_u| l.get(idx_u))?,
        Some(&Json::Object(ref m)) => m.get(p),
        Some(_) => None,
        None => None,
    };
    Ok(result)
}

fn get_in_block_params<'a>(
    block_contexts: &'a VecDeque<BlockContext>,
    p: &str,
) -> Option<&'a BlockParamHolder> {
    for bc in block_contexts {
        let v = bc.get_block_param(p);
        if v.is_some() {
            return v;
        }
    }

    None
}

pub(crate) fn merge_json(base: &Json, addition: &HashMap<&&str, &Json>) -> Json {
    let mut base_map = match base {
        Json::Object(ref m) => m.clone(),
        _ => Map::new(),
    };

    for (k, v) in addition.iter() {
        base_map.insert((*(*k)).to_string(), (*v).clone());
    }

    Json::Object(base_map)
}

impl Context {
    /// Create a context with null data
    pub fn null() -> Context {
        Context { data: Json::Null }
    }

    /// Create a context with given data
    pub fn wraps<T: Serialize>(e: T) -> Result<Context, RenderError> {
        to_value(e)
            .map_err(RenderError::from)
            .map(|d| Context { data: d })
    }

    /// Navigate the context with relative path and block scopes
    pub(crate) fn navigate<'reg, 'rc>(
        &'rc self,
        relative_path: &[PathSeg],
        block_contexts: &VecDeque<BlockContext<'reg, 'rc>>,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        // always use absolute at the moment until we get base_value lifetime issue fixed
        let resolved_visitor = parse_json_visitor(&relative_path, block_contexts, true)?;

        match resolved_visitor {
            ResolvedPath::AbsolutePath(paths) => {
                let mut ptr = Some(self.data());
                for p in paths.iter() {
                    ptr = get_data(ptr, p)?;
                }

                Ok(ptr
                    .map(|v| ScopedJson::Context(v, paths))
                    .unwrap_or_else(|| ScopedJson::Missing))
            }
            ResolvedPath::RelativePath(_paths) => {
                // relative path is disabled for now
                unreachable!()
                // let mut ptr = block_contexts.front().and_then(|blk| blk.base_value());
                // for p in paths.iter() {
                //     ptr = get_data(ptr, p)?;
                // }

                // Ok(ptr
                //     .map(|v| ScopedJson::Context(v, paths))
                //     .unwrap_or_else(|| ScopedJson::Missing))
            }
            ResolvedPath::BlockParamValue(paths, value) => {
                let mut ptr = Some(value);
                for p in paths.iter() {
                    ptr = get_data(ptr, p)?;
                }
                Ok(ptr
                    .map(|v| ScopedJson::Derived(v.clone()))
                    .unwrap_or_else(|| ScopedJson::Missing))
            }
        }
    }

    pub fn data(&self) -> &Json {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut Json {
        &mut self.data
    }
}

#[cfg(test)]
mod test {
    use crate::block::{BlockContext, BlockParams};
    use crate::context::{self, Context};
    use crate::error::RenderError;
    use crate::json::path::PathSeg;
    use crate::json::value::{self, ScopedJson};
    use serde_json::value::Map;
    use std::collections::{HashMap, VecDeque};

    fn navigate_from_root<'reg, 'rc>(
        ctx: &'rc Context,
        path: &str,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        let relative_path = PathSeg::parse(path).unwrap();
        ctx.navigate(&relative_path, &VecDeque::new())
    }

    #[derive(Serialize)]
    struct Address {
        city: String,
        country: String,
    }

    #[derive(Serialize)]
    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string()).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this").unwrap().render(),
            v.to_string()
        );
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographer".to_string()],
        };

        let ctx = Context::wraps(&person).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "./addr/country").unwrap().render(),
            "China".to_string()
        );
        assert_eq!(
            navigate_from_root(&ctx, "addr.[country]").unwrap().render(),
            "China".to_string()
        );

        let v = true;
        let ctx2 = Context::wraps(&v).unwrap();
        assert_eq!(
            navigate_from_root(&ctx2, "this").unwrap().render(),
            "true".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "titles.[0]").unwrap().render(),
            "programmer".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "age").unwrap().render(),
            "27".to_string()
        );
    }

    #[test]
    fn test_this() {
        let mut map_with_this = Map::new();
        map_with_this.insert("this".to_string(), value::to_json("hello"));
        map_with_this.insert("age".to_string(), value::to_json(5usize));
        let ctx1 = Context::wraps(&map_with_this).unwrap();

        let mut map_without_this = Map::new();
        map_without_this.insert("age".to_string(), value::to_json(4usize));
        let ctx2 = Context::wraps(&map_without_this).unwrap();

        assert_eq!(
            navigate_from_root(&ctx1, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx2, "age").unwrap().render(),
            "4".to_owned()
        );
    }

    #[test]
    fn test_merge_json() {
        let map = json!({ "age": 4 });
        let s = "hello".to_owned();
        let mut hash = HashMap::new();
        let v = value::to_json("h1");
        hash.insert(&"tag", &v);

        let ctx_a1 = Context::wraps(&context::merge_json(&map, &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a1, "age").unwrap().render(),
            "4".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a1, "tag").unwrap().render(),
            "h1".to_owned()
        );

        let ctx_a2 = Context::wraps(&context::merge_json(&value::to_json(s), &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a2, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a2, "tag").unwrap().render(),
            "h1".to_owned()
        );
    }

    #[test]
    fn test_key_name_with_this() {
        let m = btreemap! {
            "this_name".to_string() => "the_value".to_string()
        };
        let ctx = Context::wraps(&m).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this_name").unwrap().render(),
            "the_value".to_string()
        );
    }

    use serde::ser::Error as SerdeError;
    use serde::{Serialize, Serializer};

    struct UnserializableType {}

    impl Serialize for UnserializableType {
        fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            Err(SerdeError::custom("test"))
        }
    }

    #[test]
    fn test_serialize_error() {
        let d = UnserializableType {};
        assert!(Context::wraps(&d).is_err());
    }

    #[test]
    fn test_root() {
        let m = json!({
            "a" : {
                "b" : {
                    "c" : {
                        "d" : 1
                    }
                }
            },
            "b": 2
        });
        let ctx = Context::wraps(&m).unwrap();
        let mut block = BlockContext::new();
        *block.base_path_mut() = ["a".to_owned(), "b".to_owned()].to_vec();

        let mut blocks = VecDeque::new();
        blocks.push_front(block);

        assert_eq!(
            ctx.navigate(&PathSeg::parse("@root/b").unwrap(), &blocks)
                .unwrap()
                .render(),
            "2".to_string()
        );
    }

    #[test]
    fn test_block_params() {
        let m = json!([{
            "a": [1, 2]
        }, {
            "b": [2, 3]
        }]);

        let ctx = Context::wraps(&m).unwrap();
        let mut block_params = BlockParams::new();
        block_params
            .add_path("z", ["0".to_owned(), "a".to_owned()].to_vec())
            .unwrap();
        block_params.add_value("t", json!("good")).unwrap();

        let mut block = BlockContext::new();
        block.set_block_params(block_params);

        let mut blocks = VecDeque::new();
        blocks.push_front(block);

        assert_eq!(
            ctx.navigate(&PathSeg::parse("z.[1]").unwrap(), &blocks)
                .unwrap()
                .render(),
            "2".to_string()
        );
        assert_eq!(
            ctx.navigate(&PathSeg::parse("t").unwrap(), &blocks)
                .unwrap()
                .render(),
            "good".to_string()
        );
    }
}
<commit_msg>(fix) relative path of block param<commit_after>use std::collections::{HashMap, VecDeque};

use serde::Serialize;
use serde_json::value::{to_value, Map, Value as Json};

use crate::block::{BlockContext, BlockParamHolder};
use crate::error::RenderError;
use crate::grammar::Rule;
use crate::json::path::*;
use crate::json::value::ScopedJson;
use crate::util::extend;

pub type Object = HashMap<String, Json>;

/// The context wrap data you render on your templates.
///
#[derive(Debug, Clone)]
pub struct Context {
    data: Json,
}

#[derive(Debug)]
enum ResolvedPath<'a> {
    // FIXME: change to borrowed when possible
    // full path
    AbsolutePath(Vec<String>),
    // relative path and path root
    RelativePath(Vec<String>),
    // relative path against block param value
    BlockParamValue(Vec<String>, &'a Json),
}

fn parse_json_visitor<'a>(
    relative_path: &[PathSeg],
    block_contexts: &'a VecDeque<BlockContext>,
    always_for_absolute_path: bool,
) -> Result<ResolvedPath<'a>, RenderError> {
    let mut path_context_depth: i64 = 0;
    let mut with_block_param = None;
    let mut from_root = false;

    // peek relative_path for block param, @root and  "../../"
    for path_seg in relative_path {
        match path_seg {
            PathSeg::Named(the_path) => {
                if let Some((holder, base_path)) = get_in_block_params(&block_contexts, the_path) {
                    with_block_param = Some((holder, base_path));
                }
                break;
            }
            PathSeg::Ruled(the_rule) => match the_rule {
                Rule::path_root => {
                    from_root = true;
                    break;
                }
                Rule::path_up => path_context_depth += 1,
                _ => break,
            },
        }
    }

    let mut path_stack = Vec::with_capacity(relative_path.len() + 5);
    match with_block_param {
        Some((BlockParamHolder::Value(ref value), _)) => {
            merge_json_path(&mut path_stack, &relative_path[1..]);
            Ok(ResolvedPath::BlockParamValue(path_stack, value))
        }
        Some((BlockParamHolder::Path(ref paths), base_path)) => {
            extend(&mut path_stack, base_path);
            if !paths.is_empty() {
                extend(&mut path_stack, paths);
            }
            merge_json_path(&mut path_stack, &relative_path[1..]);

            Ok(ResolvedPath::AbsolutePath(path_stack))
        }
        None => {
            if path_context_depth > 0 {
                if let Some(ref context_base_path) = block_contexts
                    .get(path_context_depth as usize)
                    .map(|blk| blk.base_path())
                {
                    extend(&mut path_stack, context_base_path);
                } else {
                    // TODO: is this correct behaviour?
                    if let Some(ref base_path) = block_contexts.front().map(|blk| blk.base_path()) {
                        extend(&mut path_stack, base_path);
                    }
                }
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else if from_root {
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else if always_for_absolute_path {
                if let Some(base_path) = block_contexts.front().map(|blk| blk.base_path()) {
                    extend(&mut path_stack, base_path);
                }
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::AbsolutePath(path_stack))
            } else {
                merge_json_path(&mut path_stack, relative_path);
                Ok(ResolvedPath::RelativePath(path_stack))
            }
        }
    }
}

fn get_data<'a>(d: Option<&'a Json>, p: &str) -> Result<Option<&'a Json>, RenderError> {
    let result = match d {
        Some(&Json::Array(ref l)) => p
            .parse::<usize>()
            .map_err(RenderError::with)
            .map(|idx_u| l.get(idx_u))?,
        Some(&Json::Object(ref m)) => m.get(p),
        Some(_) => None,
        None => None,
    };
    Ok(result)
}

fn get_in_block_params<'a>(
    block_contexts: &'a VecDeque<BlockContext>,
    p: &str,
) -> Option<(&'a BlockParamHolder, &'a Vec<String>)> {
    for bc in block_contexts {
        let v = bc.get_block_param(p);
        if v.is_some() {
            return v.map(|v| (v, bc.base_path()));
        }
    }

    None
}

pub(crate) fn merge_json(base: &Json, addition: &HashMap<&&str, &Json>) -> Json {
    let mut base_map = match base {
        Json::Object(ref m) => m.clone(),
        _ => Map::new(),
    };

    for (k, v) in addition.iter() {
        base_map.insert((*(*k)).to_string(), (*v).clone());
    }

    Json::Object(base_map)
}

impl Context {
    /// Create a context with null data
    pub fn null() -> Context {
        Context { data: Json::Null }
    }

    /// Create a context with given data
    pub fn wraps<T: Serialize>(e: T) -> Result<Context, RenderError> {
        to_value(e)
            .map_err(RenderError::from)
            .map(|d| Context { data: d })
    }

    /// Navigate the context with relative path and block scopes
    pub(crate) fn navigate<'reg, 'rc>(
        &'rc self,
        relative_path: &[PathSeg],
        block_contexts: &VecDeque<BlockContext<'reg, 'rc>>,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        // always use absolute at the moment until we get base_value lifetime issue fixed
        let resolved_visitor = parse_json_visitor(&relative_path, block_contexts, true)?;

        match resolved_visitor {
            ResolvedPath::AbsolutePath(paths) => {
                let mut ptr = Some(self.data());
                for p in paths.iter() {
                    ptr = get_data(ptr, p)?;
                }

                Ok(ptr
                    .map(|v| ScopedJson::Context(v, paths))
                    .unwrap_or_else(|| ScopedJson::Missing))
            }
            ResolvedPath::RelativePath(_paths) => {
                // relative path is disabled for now
                unreachable!()
                // let mut ptr = block_contexts.front().and_then(|blk| blk.base_value());
                // for p in paths.iter() {
                //     ptr = get_data(ptr, p)?;
                // }

                // Ok(ptr
                //     .map(|v| ScopedJson::Context(v, paths))
                //     .unwrap_or_else(|| ScopedJson::Missing))
            }
            ResolvedPath::BlockParamValue(paths, value) => {
                let mut ptr = Some(value);
                for p in paths.iter() {
                    ptr = get_data(ptr, p)?;
                }
                Ok(ptr
                    .map(|v| ScopedJson::Derived(v.clone()))
                    .unwrap_or_else(|| ScopedJson::Missing))
            }
        }
    }

    pub fn data(&self) -> &Json {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut Json {
        &mut self.data
    }
}

#[cfg(test)]
mod test {
    use crate::block::{BlockContext, BlockParams};
    use crate::context::{self, Context};
    use crate::error::RenderError;
    use crate::json::path::PathSeg;
    use crate::json::value::{self, ScopedJson};
    use serde_json::value::Map;
    use std::collections::{HashMap, VecDeque};

    fn navigate_from_root<'reg, 'rc>(
        ctx: &'rc Context,
        path: &str,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        let relative_path = PathSeg::parse(path).unwrap();
        ctx.navigate(&relative_path, &VecDeque::new())
    }

    #[derive(Serialize)]
    struct Address {
        city: String,
        country: String,
    }

    #[derive(Serialize)]
    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string()).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this").unwrap().render(),
            v.to_string()
        );
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographer".to_string()],
        };

        let ctx = Context::wraps(&person).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "./addr/country").unwrap().render(),
            "China".to_string()
        );
        assert_eq!(
            navigate_from_root(&ctx, "addr.[country]").unwrap().render(),
            "China".to_string()
        );

        let v = true;
        let ctx2 = Context::wraps(&v).unwrap();
        assert_eq!(
            navigate_from_root(&ctx2, "this").unwrap().render(),
            "true".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "titles.[0]").unwrap().render(),
            "programmer".to_string()
        );

        assert_eq!(
            navigate_from_root(&ctx, "age").unwrap().render(),
            "27".to_string()
        );
    }

    #[test]
    fn test_this() {
        let mut map_with_this = Map::new();
        map_with_this.insert("this".to_string(), value::to_json("hello"));
        map_with_this.insert("age".to_string(), value::to_json(5usize));
        let ctx1 = Context::wraps(&map_with_this).unwrap();

        let mut map_without_this = Map::new();
        map_without_this.insert("age".to_string(), value::to_json(4usize));
        let ctx2 = Context::wraps(&map_without_this).unwrap();

        assert_eq!(
            navigate_from_root(&ctx1, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx2, "age").unwrap().render(),
            "4".to_owned()
        );
    }

    #[test]
    fn test_merge_json() {
        let map = json!({ "age": 4 });
        let s = "hello".to_owned();
        let mut hash = HashMap::new();
        let v = value::to_json("h1");
        hash.insert(&"tag", &v);

        let ctx_a1 = Context::wraps(&context::merge_json(&map, &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a1, "age").unwrap().render(),
            "4".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a1, "tag").unwrap().render(),
            "h1".to_owned()
        );

        let ctx_a2 = Context::wraps(&context::merge_json(&value::to_json(s), &hash)).unwrap();
        assert_eq!(
            navigate_from_root(&ctx_a2, "this").unwrap().render(),
            "[object]".to_owned()
        );
        assert_eq!(
            navigate_from_root(&ctx_a2, "tag").unwrap().render(),
            "h1".to_owned()
        );
    }

    #[test]
    fn test_key_name_with_this() {
        let m = btreemap! {
            "this_name".to_string() => "the_value".to_string()
        };
        let ctx = Context::wraps(&m).unwrap();
        assert_eq!(
            navigate_from_root(&ctx, "this_name").unwrap().render(),
            "the_value".to_string()
        );
    }

    use serde::ser::Error as SerdeError;
    use serde::{Serialize, Serializer};

    struct UnserializableType {}

    impl Serialize for UnserializableType {
        fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            Err(SerdeError::custom("test"))
        }
    }

    #[test]
    fn test_serialize_error() {
        let d = UnserializableType {};
        assert!(Context::wraps(&d).is_err());
    }

    #[test]
    fn test_root() {
        let m = json!({
            "a" : {
                "b" : {
                    "c" : {
                        "d" : 1
                    }
                }
            },
            "b": 2
        });
        let ctx = Context::wraps(&m).unwrap();
        let mut block = BlockContext::new();
        *block.base_path_mut() = ["a".to_owned(), "b".to_owned()].to_vec();

        let mut blocks = VecDeque::new();
        blocks.push_front(block);

        assert_eq!(
            ctx.navigate(&PathSeg::parse("@root/b").unwrap(), &blocks)
                .unwrap()
                .render(),
            "2".to_string()
        );
    }

    #[test]
    fn test_block_params() {
        let m = json!([{
            "a": [1, 2]
        }, {
            "b": [2, 3]
        }]);

        let ctx = Context::wraps(&m).unwrap();
        let mut block_params = BlockParams::new();
        block_params
            .add_path("z", ["0".to_owned(), "a".to_owned()].to_vec())
            .unwrap();
        block_params.add_value("t", json!("good")).unwrap();

        let mut block = BlockContext::new();
        block.set_block_params(block_params);

        let mut blocks = VecDeque::new();
        blocks.push_front(block);

        assert_eq!(
            ctx.navigate(&PathSeg::parse("z.[1]").unwrap(), &blocks)
                .unwrap()
                .render(),
            "2".to_string()
        );
        assert_eq!(
            ctx.navigate(&PathSeg::parse("t").unwrap(), &blocks)
                .unwrap()
                .render(),
            "good".to_string()
        );
    }
}
<|endoftext|>


<commit_before>//! # `context` - manage a valid repository.

use std::ops::{Deref, DerefMut};
use std::fmt;
use std::path::{Path, PathBuf};

use chrono::prelude::*;
use futures::future::{self, Either};
use futures::prelude::*;
use futures::stream;
use futures::sync::mpsc::{self, Sender, Receiver};
use futures_cpupool::CpuPool;
use globset::GlobSet;
use memmap::{Mmap, Protection};

use {BATCH_FUTURE_BUFFER_SIZE, WRITE_FUTURE_BUFFER_SIZE};
use arc_slice::{self, ArcSlice};
use errors::*;
use index::Cached;
use marshal::{ObjectHash, Marshaller, Hashed, Object, CommitObject, DirTree};
use repository::Repository;
use split::SliceChunker;
use store::{Store, Empty};
use trace::Trace;

/// A context for marshalling and local operations on a repository. `RemoteContext`s must be built
/// from a `Context`.
///
/// `Context` may optionally be supplied with a type `T` implementing `Trace`. This "trace object"
/// is useful for doing things like tracking the progress of long-running operations.
pub struct Context<'a, T: Trace, S: Store> {
    repository: &'a mut Repository,

    trace: T,
    store: S,

    marshal_pool: CpuPool,

    marshal_tx: Sender<Hashed>,
    writes: Box<Future<Item = (), Error = Error> + Send>,

    index_tx: Sender<(PathBuf, ObjectHash)>,
    index_rx: Receiver<(PathBuf, ObjectHash)>,
}

impl<'a, T: Trace, S: Store> Deref for Context<'a, T, S> {
    type Target = Repository;

    fn deref(&self) -> &Self::Target {
        &*self.repository
    }
}

impl<'a, T: Trace, S: Store> DerefMut for Context<'a, T, S> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut *self.repository
    }
}

impl<'a, T: Trace + fmt::Debug, S: Store + fmt::Debug> fmt::Debug for Context<'a, T, S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Context")
            .field("repository", &self.repository)
            .field("trace", &self.trace)
            .field("store", &self.store)
            .field("marshal_pool", &self.marshal_pool)
            .field("marshal_tx", &self.marshal_tx)
            .finish()
    }
}

impl<'a, T: Trace, S: Store> Context<'a, T, S> {
    /// Create a context from a loaded repository, with a supplied trace object.
    pub fn new(
        repository: &'a mut Repository,
        trace: T,
        store: S,
        marshal_pool: &CpuPool,
        io_pool: &CpuPool,
    ) -> Self {
        let (marshal_tx, marshal_rx) = mpsc::channel(BATCH_FUTURE_BUFFER_SIZE);
        let (index_tx, index_rx) = mpsc::channel(BATCH_FUTURE_BUFFER_SIZE);

        let writes = {
            let trace = trace.clone();
            let store = store.clone();
            let writes_unboxed = marshal_rx
                .map_err(|()| unreachable!("mpsc receivers never error"))
                .map(move |hashed: Hashed| {
                    let hash = *hashed.as_hash();
                    let trace = trace.clone();

                    trace.on_write_object_start(&hash);
                    store.write_object(hashed).map(move |fresh| {
                        trace.on_write_object_finish(&hash, fresh);
                    })
                })
                .buffer_unordered(WRITE_FUTURE_BUFFER_SIZE)
                .for_each(|_| Ok(()));

            Box::new(io_pool.spawn(writes_unboxed))
        };

        Self {
            repository,

            trace,
            store,

            marshal_pool: marshal_pool.clone(),

            marshal_tx,
            writes,

            index_tx,
            index_rx,
        }
    }

    pub fn split_file<P: AsRef<Path>>(
        &self,
        path: P,
    ) -> Box<Stream<Item = ArcSlice, Error = Error> + Send> {
        let trace = self.trace.clone();
        let slice_res = Mmap::open_path(path, Protection::Read).map(|mmap| {
            trace.on_split_begin(mmap.len() as u64);
            arc_slice::mapped(mmap)
        });

        let stream_future = {
            async_block! {
                let mut offset = 0u64;
                let slices = SliceChunker::new(slice_res?).inspect(move |chunk| {
                    trace.on_split_chunk(offset, chunk);
                    offset += chunk.len() as u64;
                });

                Ok(stream::iter_ok(slices))
            }
        };

        Box::new(stream_future.flatten_stream())
    }

    pub fn read_head(&self) -> Box<Future<Item = Option<CommitObject>, Error = Error> + Send> {
        match self.refs.head() {
            Some(commit_hash) => {
                let async = self.store.read_object(commit_hash).and_then(
                    move |object| {
                        match object {
                            Object::Commit(commit_object) => Ok(Some(commit_object)),
                            _ => bail!(ErrorKind::ObjectNotACommit(commit_hash)),
                        }
                    },
                );

                Box::new(async)
            }

            None => Box::new(future::ok(None)),
        }
    }

    pub fn write_file<U>(&self, stream: U) -> Box<Future<Item = ObjectHash, Error = Error> + Send>
    where
        U: Stream<Item = ArcSlice, Error = Error> + Send + 'static,
    {
        let marshal_tx = self.marshal_tx.clone();
        let marshaller = Marshaller::with_trace(marshal_tx, self.trace.clone());

        Box::new(self.marshal_pool.spawn(marshaller.process_chunks(stream)))
    }

    pub fn write_subtree<U>(
        &self,
        stream: U,
    ) -> Box<Future<Item = ObjectHash, Error = Error> + Send>
    where
        U: Stream<Item = (PathBuf, ObjectHash), Error = Error> + Send + 'static,
    {
        let marshal_tx = self.marshal_tx.clone();
        let marshaller = Marshaller::with_trace(marshal_tx, self.trace.clone());
        let hash_future = stream
            .map(|(path, hash)| (path, Some(hash)))
            .collect()
            .and_then(|entries| {
                DirTree::delta(Empty, None, entries).map_err(|err| {
                    Error::with_chain(Error::from_kind(ErrorKind::DirTreeDelta), err)
                })
            })
            .and_then(move |dir_tree| marshaller.process_dir_tree(dir_tree));

        Box::new(self.marshal_pool.spawn(hash_future))
    }

    pub fn write_commit(
        &self,
        include_opt: Option<&GlobSet>,
        exclude_opt: Option<&GlobSet>,
        parents: Vec<ObjectHash>,
        message: String,
        timestamp: DateTime<Utc>,
    ) -> Box<Future<Item = ObjectHash, Error = Error> + Send> {
        let marshaller = Marshaller::with_trace(self.marshal_tx.clone(), self.trace.clone());

        let subtree_future = {
            let entries_iter = self.index.iter()
                .filter(|&(path, entry)| {
                    let is_included = include_opt
                        .map(|include| include.is_match(path))
                        .unwrap_or(false);
                    let is_excluded = exclude_opt
                        .map(|exclude| exclude.is_match(path))
                        .unwrap_or(false);

                    (is_included || entry.added || entry.tracked) && !is_excluded
                })
                .map(|(path, entry)| {
                    match entry.get() {
                        Some(Cached::Hashed(object_hash)) => Either::A(future::ok((path.to_owned(), Some(object_hash)))),
                        Some(Cached::Removed) => Either::A(future::ok((path.to_owned(), None))),

                        // If the file has no hash in the cache *or* has an invalid cache entry, we must
                        // split and hash it.
                        Some(Cached::Unhashed) | None => {
                            let path = path.to_owned();
                            let chunk_stream = self.split_file(&path);
                            let index_tx = self.index_tx.clone();
                            let hash_future = self.write_file(chunk_stream);

                            Either::B(hash_future.and_then(|object_hash| {
                                index_tx
                                    .send((path.clone(), object_hash))
                                    .map(move |_| (path, Some(object_hash)))
                                    .map_err(|_| Error::from_kind(ErrorKind::Absurd))
                            }))
                        }
                    }
                });

            let marshaller = marshaller.clone();
            let store = self.store.clone();
            stream::futures_unordered(entries_iter)
                .collect()
                .join(self.read_head().map(|commit_opt| {
                    commit_opt.map(|commit| commit.subtree)
                }))
                .and_then(move |(ops, root)| DirTree::delta(store, root, ops))
                .and_then(move |dir_tree| marshaller.process_dir_tree(dir_tree))
        };

        let commit_future = subtree_future.and_then(move |subtree| {
            marshaller.process(CommitObject {
                subtree,
                parents,
                message,
                timestamp,
            })
        });

        Box::new(self.marshal_pool.spawn(commit_future))
    }

    pub fn store(&self) -> &S {
        &self.store
    }

    pub fn close(self) -> Box<Future<Item = (), Error = Error> + Send + 'a> {
        let repository = self.repository;
        let close_future = self.writes.join(
            self.index_rx.map_err(|_| Error::from_kind(ErrorKind::Absurd)).for_each(move |(path, object_hash)| {
                repository.index.clean(path, object_hash)
            }),
        ).map(|((), ())| ());

        Box::new(close_future)
    }
}
<commit_msg>context.rs: add .read_commit()<commit_after>//! # `context` - manage a valid repository.

use std::ops::{Deref, DerefMut};
use std::fmt;
use std::path::{Path, PathBuf};

use chrono::prelude::*;
use futures::future::{self, Either};
use futures::prelude::*;
use futures::stream;
use futures::sync::mpsc::{self, Sender, Receiver};
use futures_cpupool::CpuPool;
use globset::GlobSet;
use memmap::{Mmap, Protection};

use {BATCH_FUTURE_BUFFER_SIZE, WRITE_FUTURE_BUFFER_SIZE};
use arc_slice::{self, ArcSlice};
use errors::*;
use index::Cached;
use marshal::{ObjectHash, Marshaller, Hashed, Object, CommitObject, DirTree};
use repository::Repository;
use split::SliceChunker;
use store::{Store, Empty};
use trace::Trace;

/// A context for marshalling and local operations on a repository. `RemoteContext`s must be built
/// from a `Context`.
///
/// `Context` may optionally be supplied with a type `T` implementing `Trace`. This "trace object"
/// is useful for doing things like tracking the progress of long-running operations.
pub struct Context<'a, T: Trace, S: Store> {
    repository: &'a mut Repository,

    trace: T,
    store: S,

    marshal_pool: CpuPool,

    marshal_tx: Sender<Hashed>,
    writes: Box<Future<Item = (), Error = Error> + Send>,

    index_tx: Sender<(PathBuf, ObjectHash)>,
    index_rx: Receiver<(PathBuf, ObjectHash)>,
}

impl<'a, T: Trace, S: Store> Deref for Context<'a, T, S> {
    type Target = Repository;

    fn deref(&self) -> &Self::Target {
        &*self.repository
    }
}

impl<'a, T: Trace, S: Store> DerefMut for Context<'a, T, S> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut *self.repository
    }
}

impl<'a, T: Trace + fmt::Debug, S: Store + fmt::Debug> fmt::Debug for Context<'a, T, S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Context")
            .field("repository", &self.repository)
            .field("trace", &self.trace)
            .field("store", &self.store)
            .field("marshal_pool", &self.marshal_pool)
            .field("marshal_tx", &self.marshal_tx)
            .finish()
    }
}

impl<'a, T: Trace, S: Store> Context<'a, T, S> {
    /// Create a context from a loaded repository, with a supplied trace object.
    pub fn new(
        repository: &'a mut Repository,
        trace: T,
        store: S,
        marshal_pool: &CpuPool,
        io_pool: &CpuPool,
    ) -> Self {
        let (marshal_tx, marshal_rx) = mpsc::channel(BATCH_FUTURE_BUFFER_SIZE);
        let (index_tx, index_rx) = mpsc::channel(BATCH_FUTURE_BUFFER_SIZE);

        let writes = {
            let trace = trace.clone();
            let store = store.clone();
            let writes_unboxed = marshal_rx
                .map_err(|()| unreachable!("mpsc receivers never error"))
                .map(move |hashed: Hashed| {
                    let hash = *hashed.as_hash();
                    let trace = trace.clone();

                    trace.on_write_object_start(&hash);
                    store.write_object(hashed).map(move |fresh| {
                        trace.on_write_object_finish(&hash, fresh);
                    })
                })
                .buffer_unordered(WRITE_FUTURE_BUFFER_SIZE)
                .for_each(|_| Ok(()));

            Box::new(io_pool.spawn(writes_unboxed))
        };

        Self {
            repository,

            trace,
            store,

            marshal_pool: marshal_pool.clone(),

            marshal_tx,
            writes,

            index_tx,
            index_rx,
        }
    }

    pub fn split_file<P: AsRef<Path>>(
        &self,
        path: P,
    ) -> Box<Stream<Item = ArcSlice, Error = Error> + Send> {
        let trace = self.trace.clone();
        let slice_res = Mmap::open_path(path, Protection::Read).map(|mmap| {
            trace.on_split_begin(mmap.len() as u64);
            arc_slice::mapped(mmap)
        });

        let stream_future = {
            async_block! {
                let mut offset = 0u64;
                let slices = SliceChunker::new(slice_res?).inspect(move |chunk| {
                    trace.on_split_chunk(offset, chunk);
                    offset += chunk.len() as u64;
                });

                Ok(stream::iter_ok(slices))
            }
        };

        Box::new(stream_future.flatten_stream())
    }

    pub fn read_commit(
        &self,
        commit_hash: ObjectHash,
    ) -> Box<Future<Item = CommitObject, Error = Error> + Send> {
        let async = self.store.read_object(commit_hash).and_then(
            move |object| {
                match object {
                    Object::Commit(commit_object) => Ok(commit_object),
                    _ => bail!(ErrorKind::ObjectNotACommit(commit_hash)),
                }
            },
        );

        Box::new(async)
    }

    pub fn read_head(&self) -> Box<Future<Item = Option<CommitObject>, Error = Error> + Send> {
        match self.refs.head() {
            Some(commit_hash) => Box::new(self.read_commit(commit_hash).map(Some)),
            None => Box::new(future::ok(None)),
        }
    }

    pub fn write_file<U>(&self, stream: U) -> Box<Future<Item = ObjectHash, Error = Error> + Send>
    where
        U: Stream<Item = ArcSlice, Error = Error> + Send + 'static,
    {
        let marshal_tx = self.marshal_tx.clone();
        let marshaller = Marshaller::with_trace(marshal_tx, self.trace.clone());

        Box::new(self.marshal_pool.spawn(marshaller.process_chunks(stream)))
    }

    pub fn write_subtree<U>(
        &self,
        stream: U,
    ) -> Box<Future<Item = ObjectHash, Error = Error> + Send>
    where
        U: Stream<Item = (PathBuf, ObjectHash), Error = Error> + Send + 'static,
    {
        let marshal_tx = self.marshal_tx.clone();
        let marshaller = Marshaller::with_trace(marshal_tx, self.trace.clone());
        let hash_future = stream
            .map(|(path, hash)| (path, Some(hash)))
            .collect()
            .and_then(|entries| {
                DirTree::delta(Empty, None, entries).map_err(|err| {
                    Error::with_chain(Error::from_kind(ErrorKind::DirTreeDelta), err)
                })
            })
            .and_then(move |dir_tree| marshaller.process_dir_tree(dir_tree));

        Box::new(self.marshal_pool.spawn(hash_future))
    }

    pub fn write_commit(
        &self,
        include_opt: Option<&GlobSet>,
        exclude_opt: Option<&GlobSet>,
        parents: Vec<ObjectHash>,
        message: String,
        timestamp: DateTime<Utc>,
    ) -> Box<Future<Item = ObjectHash, Error = Error> + Send> {
        let marshaller = Marshaller::with_trace(self.marshal_tx.clone(), self.trace.clone());

        let subtree_future = {
            let entries_iter = self.index.iter()
                .filter(|&(path, entry)| {
                    let is_included = include_opt
                        .map(|include| include.is_match(path))
                        .unwrap_or(false);
                    let is_excluded = exclude_opt
                        .map(|exclude| exclude.is_match(path))
                        .unwrap_or(false);

                    (is_included || entry.added || entry.tracked) && !is_excluded
                })
                .map(|(path, entry)| {
                    match entry.get() {
                        Some(Cached::Hashed(object_hash)) => Either::A(future::ok((path.to_owned(), Some(object_hash)))),
                        Some(Cached::Removed) => Either::A(future::ok((path.to_owned(), None))),

                        // If the file has no hash in the cache *or* has an invalid cache entry, we must
                        // split and hash it.
                        Some(Cached::Unhashed) | None => {
                            let path = path.to_owned();
                            let chunk_stream = self.split_file(&path);
                            let index_tx = self.index_tx.clone();
                            let hash_future = self.write_file(chunk_stream);

                            Either::B(hash_future.and_then(|object_hash| {
                                index_tx
                                    .send((path.clone(), object_hash))
                                    .map(move |_| (path, Some(object_hash)))
                                    .map_err(|_| Error::from_kind(ErrorKind::Absurd))
                            }))
                        }
                    }
                });

            let marshaller = marshaller.clone();
            let store = self.store.clone();
            stream::futures_unordered(entries_iter)
                .collect()
                .join(self.read_head().map(|commit_opt| {
                    commit_opt.map(|commit| commit.subtree)
                }))
                .and_then(move |(ops, root)| DirTree::delta(store, root, ops))
                .and_then(move |dir_tree| marshaller.process_dir_tree(dir_tree))
        };

        let commit_future = subtree_future.and_then(move |subtree| {
            marshaller.process(CommitObject {
                subtree,
                parents,
                message,
                timestamp,
            })
        });

        Box::new(self.marshal_pool.spawn(commit_future))
    }

    pub fn store(&self) -> &S {
        &self.store
    }

    pub fn close(self) -> Box<Future<Item = (), Error = Error> + Send + 'a> {
        let repository = self.repository;
        let close_future = self.writes.join(
            self.index_rx.map_err(|_| Error::from_kind(ErrorKind::Absurd)).for_each(move |(path, object_hash)| {
                repository.index.clean(path, object_hash)
            }),
        ).map(|((), ())| ());

        Box::new(close_future)
    }
}
<|endoftext|>


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

// TODO Setup contributor license agreement.

//! this is context class to use autograd.

extern crate std;

// TODO #[inline] where appropriate.

pub trait Context<T>: std::marker::Sized where T: std::num::Float {
    // public functions

    fn new() -> Self {
        // TODO implement correctly.
        // let size: usize = (std::u32::MAX as usize) / 2;
        Context::<T>::new_tmp()
    }

    fn new_variable(&self, value: T) -> super::float::Float<T, Self> {
        super::float::float_new(value, <Self as Context<T>>::get_new_variable_index())
    }

    fn differentiate(&self, float: super::float::Float<T, Self>) {
        unsafe {
            // let count = <Self as Context<T>>::get_recorded_variables_count();
            *<Self as Context<T>>::get_result_derivatives().offset(super::float::float_get_index(&float) as isize) = std::num::Float::one();
            for i in (0..(*<Self as Context<T>>::get_recorded_entries_count())).rev() {
                let lhs_index = *<Self as Context<T>>::get_lhs_indices().offset(i as isize);
                let rhs_index = *<Self as Context<T>>::get_rhs_indices().offset(i as isize);
                *<Self as Context<T>>::get_result_derivatives().offset(rhs_index as isize) =
                    *<Self as Context<T>>::get_result_derivatives().offset(rhs_index as isize)
                    + (*<Self as Context<T>>::get_result_derivatives().offset(lhs_index as isize)
                       * *<Self as Context<T>>::get_adjoints().offset(i as isize));

                let t = *<Self as Context<T>>::get_result_derivatives().offset(i as isize);
            }
        }
    }

    fn get_derivative(&self, float: super::float::Float<T, Self>) -> T {
        let float_index_offset = super::float::float_get_index(&float) as isize;
        unsafe {
            *<Self as Context<T>>::get_result_derivatives().offset(float_index_offset)
        }
    }

    // Private functions

    fn get_new_variable_index() -> usize {
        let count = <Self as Context<T>>::get_recorded_variables_count();
        let index = *count;
        *count += 1;
        index
    }

    fn get_new_entry_index() -> usize {
        let count = <Self as Context<T>>::get_recorded_entries_count();
        let index = *count;
        *count += 1;
        index
    }

    fn unary_operation(adjoint: T, rhs_index: usize) -> usize {
        let lhs_index = <Self as Context<T>>::get_new_variable_index();
        let recorded_entries_count_offset = <Self as Context<T>>::get_new_entry_index() as isize;
        unsafe {
            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset) = adjoint;
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset) = rhs_index;
        }
        lhs_index
    }

    fn binary_operation(adjoints: &[T; 2],
                        rhs_indices: &[usize; 2]) -> usize {
        let lhs_index = <Self as Context<T>>::get_new_variable_index();
        let recorded_entries_count_offset_1 = <Self as Context<T>>::get_new_entry_index() as isize;
        let recorded_entries_count_offset_2 = <Self as Context<T>>::get_new_entry_index() as isize;

        unsafe {
            // TODO is indexing inefficient?
            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset_1) = adjoints[0];
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset_1) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset_1) = rhs_indices[0];

            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset_2) = adjoints[1];
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset_2) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset_2) = rhs_indices[1];
        }
        lhs_index
    }

    fn get_recorded_variables_count<'a>() -> &'a mut usize;
    fn get_recorded_entries_count<'a>() -> &'a mut usize;
    fn get_adjoints<'a>() -> &'a mut*mut T;
    fn get_lhs_indices<'a>() -> &'a mut*mut usize;
    fn get_rhs_indices<'a>() -> &'a mut*mut usize;
    fn get_result_derivatives<'a>() -> &'a mut*mut T;

    fn new_tmp() -> Self;
}

pub struct ContextImpl {
    // TODO this is to keep the struct construction private. Remove when we don't need it.
    _private: (),
}

impl Context<f32> for ContextImpl {
    fn get_recorded_variables_count<'a>() -> &'a mut usize {
        #[thread_local]
        static mut ptr : usize = 0;
        unsafe {
            &mut ptr
        }
    }
    fn get_recorded_entries_count<'a>() -> &'a mut usize {
        #[thread_local]
        static mut ptr : usize = 0;
        unsafe {
            &mut ptr
        }
    }
    fn get_adjoints<'a>() -> &'a mut*mut f32 {
        #[thread_local]
        static mut ptr : *mut f32 = 0 as *mut f32;
        unsafe {
            &mut ptr
        }
    }
    fn get_lhs_indices<'a>() -> &'a mut*mut usize {
        #[thread_local]
        static mut ptr : *mut usize = 0 as *mut usize;
        unsafe {
            &mut ptr
        }
    }
    fn get_rhs_indices<'a>() -> &'a mut*mut usize{
        #[thread_local]
        static mut ptr : *mut usize = 0 as *mut usize;
        unsafe {
            &mut ptr
        }
    }

    fn get_result_derivatives<'a>() -> &'a mut*mut f32 {
        #[thread_local]
        static mut ptr : *mut f32 = 0 as *mut f32;
        unsafe {
            &mut ptr
        }
    }

    fn new_tmp() -> Self {
        // TODO implement

        let capacity: usize = 1000;

        // TODO use checked_mul?
        //      example : let usize_size = capacity.checked_mul(std::mem::size_of::<usize>()).expect("capacity overflow");
        let usize_size = capacity * std::mem::size_of::<usize>();
        let f32_size = capacity * std::mem::size_of::<f32>();
        // std::rt::heap::allocate(f32_size, mem::min_align_of::<T>())

        unsafe {
            *<Self as Context<f32>>::get_recorded_variables_count() = 0;
            *<Self as Context<f32>>::get_recorded_entries_count() = 0;
            *<Self as Context<f32>>::get_adjoints() = std::rt::heap::allocate(f32_size, std::mem::align_of::<f32>()) as *mut f32;
            *<Self as Context<f32>>::get_lhs_indices() = std::rt::heap::allocate(usize_size, std::mem::align_of::<usize>()) as *mut usize;
            *<Self as Context<f32>>::get_rhs_indices() = std::rt::heap::allocate(usize_size, std::mem::align_of::<usize>()) as *mut usize;
            // TODO we don't have to allocate get_result_derivatives now, isn't it?
            *<Self as Context<f32>>::get_result_derivatives() = std::rt::heap::allocate(f32_size, std::mem::align_of::<f32>()) as *mut f32;
        }
        ContextImpl{_private: ()}
    }
}

// TODO implement safe lock mutex.
// impl ContextImpl {
//     fn get_mutex() {
//         #[thread_local]
//         static MUTEX : std::sync::StaticMutex = std::sync::MUTEX_INIT;
//     }
// }

impl std::ops::Drop for ContextImpl {
    fn drop(&mut self) {
        // *Context::<f32>::get_recorded_variables_count(None::<Self>) = 0;
        // *Context::<f32>::get_adjoints(None::<Self>) = 0;
        // TODO implement.

        let capacity: usize = 1000;
        let usize_size = capacity * std::mem::size_of::<usize>();
        let f32_size = capacity * std::mem::size_of::<f32>();

        unsafe {
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_adjoints() as *mut u8, f32_size, std::mem::align_of::<f32>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_lhs_indices() as *mut u8, usize_size, std::mem::align_of::<usize>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_rhs_indices() as *mut u8, usize_size, std::mem::align_of::<usize>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_result_derivatives() as *mut u8, f32_size, std::mem::align_of::<f32>());
        }
    }
}
<commit_msg>Add a |differentiate(...)| function TODO.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// TODO Setup contributor license agreement.

//! this is context class to use autograd.

extern crate std;

// TODO #[inline] where appropriate.

pub trait Context<T>: std::marker::Sized where T: std::num::Float {
    // public functions

    fn new() -> Self {
        // TODO implement correctly.
        // let size: usize = (std::u32::MAX as usize) / 2;
        Context::<T>::new_tmp()
    }

    fn new_variable(&self, value: T) -> super::float::Float<T, Self> {
        super::float::float_new(value, <Self as Context<T>>::get_new_variable_index())
    }

    fn differentiate(&self, float: super::float::Float<T, Self>) {
        // TODO The current implementation is not performant and dirty.
        unsafe {
            // let count = <Self as Context<T>>::get_recorded_variables_count();
            *<Self as Context<T>>::get_result_derivatives().offset(super::float::float_get_index(&float) as isize) = std::num::Float::one();
            for i in (0..(*<Self as Context<T>>::get_recorded_entries_count())).rev() {
                let lhs_index = *<Self as Context<T>>::get_lhs_indices().offset(i as isize);
                let rhs_index = *<Self as Context<T>>::get_rhs_indices().offset(i as isize);
                *<Self as Context<T>>::get_result_derivatives().offset(rhs_index as isize) =
                    *<Self as Context<T>>::get_result_derivatives().offset(rhs_index as isize)
                    + (*<Self as Context<T>>::get_result_derivatives().offset(lhs_index as isize)
                       * *<Self as Context<T>>::get_adjoints().offset(i as isize));

                let t = *<Self as Context<T>>::get_result_derivatives().offset(i as isize);
            }
        }
    }

    fn get_derivative(&self, float: super::float::Float<T, Self>) -> T {
        let float_index_offset = super::float::float_get_index(&float) as isize;
        unsafe {
            *<Self as Context<T>>::get_result_derivatives().offset(float_index_offset)
        }
    }

    // Private functions

    fn get_new_variable_index() -> usize {
        let count = <Self as Context<T>>::get_recorded_variables_count();
        let index = *count;
        *count += 1;
        index
    }

    fn get_new_entry_index() -> usize {
        let count = <Self as Context<T>>::get_recorded_entries_count();
        let index = *count;
        *count += 1;
        index
    }

    fn unary_operation(adjoint: T, rhs_index: usize) -> usize {
        let lhs_index = <Self as Context<T>>::get_new_variable_index();
        let recorded_entries_count_offset = <Self as Context<T>>::get_new_entry_index() as isize;
        unsafe {
            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset) = adjoint;
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset) = rhs_index;
        }
        lhs_index
    }

    fn binary_operation(adjoints: &[T; 2],
                        rhs_indices: &[usize; 2]) -> usize {
        let lhs_index = <Self as Context<T>>::get_new_variable_index();
        let recorded_entries_count_offset_1 = <Self as Context<T>>::get_new_entry_index() as isize;
        let recorded_entries_count_offset_2 = <Self as Context<T>>::get_new_entry_index() as isize;

        unsafe {
            // TODO is indexing inefficient?
            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset_1) = adjoints[0];
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset_1) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset_1) = rhs_indices[0];

            *<Self as Context<T>>::get_adjoints().offset(recorded_entries_count_offset_2) = adjoints[1];
            *<Self as Context<T>>::get_lhs_indices().offset(recorded_entries_count_offset_2) = lhs_index;
            *<Self as Context<T>>::get_rhs_indices().offset(recorded_entries_count_offset_2) = rhs_indices[1];
        }
        lhs_index
    }

    fn get_recorded_variables_count<'a>() -> &'a mut usize;
    fn get_recorded_entries_count<'a>() -> &'a mut usize;
    fn get_adjoints<'a>() -> &'a mut*mut T;
    fn get_lhs_indices<'a>() -> &'a mut*mut usize;
    fn get_rhs_indices<'a>() -> &'a mut*mut usize;
    fn get_result_derivatives<'a>() -> &'a mut*mut T;

    fn new_tmp() -> Self;
}

pub struct ContextImpl {
    // TODO this is to keep the struct construction private. Remove when we don't need it.
    _private: (),
}

impl Context<f32> for ContextImpl {
    fn get_recorded_variables_count<'a>() -> &'a mut usize {
        #[thread_local]
        static mut ptr : usize = 0;
        unsafe {
            &mut ptr
        }
    }
    fn get_recorded_entries_count<'a>() -> &'a mut usize {
        #[thread_local]
        static mut ptr : usize = 0;
        unsafe {
            &mut ptr
        }
    }
    fn get_adjoints<'a>() -> &'a mut*mut f32 {
        #[thread_local]
        static mut ptr : *mut f32 = 0 as *mut f32;
        unsafe {
            &mut ptr
        }
    }
    fn get_lhs_indices<'a>() -> &'a mut*mut usize {
        #[thread_local]
        static mut ptr : *mut usize = 0 as *mut usize;
        unsafe {
            &mut ptr
        }
    }
    fn get_rhs_indices<'a>() -> &'a mut*mut usize{
        #[thread_local]
        static mut ptr : *mut usize = 0 as *mut usize;
        unsafe {
            &mut ptr
        }
    }

    fn get_result_derivatives<'a>() -> &'a mut*mut f32 {
        #[thread_local]
        static mut ptr : *mut f32 = 0 as *mut f32;
        unsafe {
            &mut ptr
        }
    }

    fn new_tmp() -> Self {
        // TODO implement

        let capacity: usize = 1000;

        // TODO use checked_mul?
        //      example : let usize_size = capacity.checked_mul(std::mem::size_of::<usize>()).expect("capacity overflow");
        let usize_size = capacity * std::mem::size_of::<usize>();
        let f32_size = capacity * std::mem::size_of::<f32>();
        // std::rt::heap::allocate(f32_size, mem::min_align_of::<T>())

        unsafe {
            *<Self as Context<f32>>::get_recorded_variables_count() = 0;
            *<Self as Context<f32>>::get_recorded_entries_count() = 0;
            *<Self as Context<f32>>::get_adjoints() = std::rt::heap::allocate(f32_size, std::mem::align_of::<f32>()) as *mut f32;
            *<Self as Context<f32>>::get_lhs_indices() = std::rt::heap::allocate(usize_size, std::mem::align_of::<usize>()) as *mut usize;
            *<Self as Context<f32>>::get_rhs_indices() = std::rt::heap::allocate(usize_size, std::mem::align_of::<usize>()) as *mut usize;
            // TODO we don't have to allocate get_result_derivatives now, isn't it?
            *<Self as Context<f32>>::get_result_derivatives() = std::rt::heap::allocate(f32_size, std::mem::align_of::<f32>()) as *mut f32;
        }
        ContextImpl{_private: ()}
    }
}

// TODO implement safe lock mutex.
// impl ContextImpl {
//     fn get_mutex() {
//         #[thread_local]
//         static MUTEX : std::sync::StaticMutex = std::sync::MUTEX_INIT;
//     }
// }

impl std::ops::Drop for ContextImpl {
    fn drop(&mut self) {
        // *Context::<f32>::get_recorded_variables_count(None::<Self>) = 0;
        // *Context::<f32>::get_adjoints(None::<Self>) = 0;
        // TODO implement.

        let capacity: usize = 1000;
        let usize_size = capacity * std::mem::size_of::<usize>();
        let f32_size = capacity * std::mem::size_of::<f32>();

        unsafe {
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_adjoints() as *mut u8, f32_size, std::mem::align_of::<f32>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_lhs_indices() as *mut u8, usize_size, std::mem::align_of::<usize>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_rhs_indices() as *mut u8, usize_size, std::mem::align_of::<usize>());
            std::rt::heap::deallocate(*<Self as Context<f32>>::get_result_derivatives() as *mut u8, f32_size, std::mem::align_of::<f32>());
        }
    }
}
<|endoftext|>


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

use std::error::FromError;
use std::io;
use std::mem;
use std::result;
use std::io::ReadExt;

use iter::{RexIterExt, ResultIterExt};

/// `Error` is used to report errors that occur within the decoder.
pub enum Error {
    /// `EOF` indicates that record source ended before it could be fully decoded.
    EOF,

    /// `IoError` is used to pass through std::io errors.
    IoError(io::Error),
}

impl FromError<io::Error> for Error {
    fn from_error(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

/// `read_uvarint` reads a varint encoded `u64` from `r`.
pub fn read_uvarint<R>(r: &mut R) -> Result<u64, Error>
    where R: io::Read {

    let itr = r.bytes()
        .take_while_incl(|x| match x { &Ok(x) => x >= 0x80, _ => true });

    // The Ok(try!(..)) just lets us convert from io::Error to Error
    result::fold(itr, 0, |sum, x| (sum << 7) + (x & 0x7F) as u64)
        .map_err(FromError::from_error)
}

/// `read_varint` reads a zig-zag varint encoded `i64` from `r`.
pub fn read_varint<R>(r: &mut R) -> Result<i64, Error>
    where R: io::Read {

    let ux = try!(read_uvarint(r));

    Ok( if ux & 1 != 0 {
        let x = (!ux >> 1) as i64;
        -x
    } else {
        let x = (ux >> 1) as i64;
        x
    })
}

/// `read_u8` reads a single byte from `r`.
pub fn read_u8<R>(r: &mut R) -> Result<u8, Error>
    where R: io::Read {

    r.bytes()
        .take_or_err(1, Error::EOF)
        .next()
        // take_or_err guarantees that we'll get an Error at worst.
        .unwrap()
}

/// `read_le_u16` reads 2 bytes as a little endian `u16` from 'r'
pub fn read_le_u16<R>(r: &mut R) -> Result<u16, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(2, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u16)
}

/// `read_le_u32` reads 4 bytes as a little endian `u32` from 'r'
pub fn read_le_u32<R>(r: &mut R) -> Result<u32, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(4, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u32)
}

/// `read_le_u64` reads 8 bytes as a little endian `u64` from 'r'
pub fn read_le_u64<R>(r: &mut R) -> Result<u64, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(8, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u64)
}

/// `read_i8` reads a single byte from `r`, as a 2's complement `i8`
pub fn read_i8<R>(r: &mut R) -> Result<i8, Error>
    where R: io::Read {

    Ok(try!(read_u8(r)) as i8)
}

/// `read_le_i16` reads 2 bytes as a little endian 2's complement `i16` from `r`.
pub fn read_le_i16<R>(r: &mut R) -> Result<i16, Error>
    where R: io::Read {

    Ok(try!(read_le_u16(r)) as i16)
}

/// `read_le_i32` reads 4 bytes as a little endian 2's complement `i32` from `r`.
pub fn read_le_i32<R>(r: &mut R) -> Result<i32, Error>
    where R: io::Read {

    Ok(try!(read_le_u32(r)) as i32)
}

/// `read_le_i64` reads 8 bytes as a little endian 2's complement `i64` from `r`.
pub fn read_le_i64<R>(r: &mut R) -> Result<i64, Error>
    where R: io::Read {

    Ok(try!(read_le_u64(r)) as i64)
}

/// `read_le_f32` reads 8 bytes as a little endian ieee-754 binary32 encoded `f32` from `r`.
pub fn read_le_f32<R>(r: &mut R) -> Result<f32, Error>
    where R: io::Read {

    let u = try!(read_le_u32(r));

    Ok(unsafe { mem::transmute(u) })
}

/// `read_le_f64` reads 8 bytes as a little endian ieee-754 binary64 encoded `f64` from `r`.
pub fn read_le_f64<R>(r: &mut R) -> Result<f64, Error>
    where R: io::Read {

    let u = try!(read_le_u64(r));

    Ok(unsafe { mem::transmute(u) })
}
<commit_msg>Hide decoding functions<commit_after>// Copyright (c) 2015, Sam Payson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::error::FromError;
use std::io;
use std::mem;
use std::result;
use std::io::ReadExt;

use iter::{RexIterExt, ResultIterExt};

/// `Error` is used to report errors that occur within the decoder.
pub enum Error {
    /// `EOF` indicates that record source ended before it could be fully decoded.
    EOF,

    /// `IoError` is used to pass through std::io errors.
    IoError(io::Error),
}

impl FromError<io::Error> for Error {
    fn from_error(err: io::Error) -> Error {
        Error::IoError(err)
    }
}

/// `read_uvarint` reads a varint encoded `u64` from `r`.
fn read_uvarint<R>(r: &mut R) -> Result<u64, Error>
    where R: io::Read {

    let itr = r.bytes()
        .take_while_incl(|x| match x { &Ok(x) => x >= 0x80, _ => true });

    // The Ok(try!(..)) just lets us convert from io::Error to Error
    result::fold(itr, 0, |sum, x| (sum << 7) + (x & 0x7F) as u64)
        .map_err(FromError::from_error)
}

/// `read_varint` reads a zig-zag varint encoded `i64` from `r`.
fn read_varint<R>(r: &mut R) -> Result<i64, Error>
    where R: io::Read {

    let ux = try!(read_uvarint(r));

    Ok( if ux & 1 != 0 {
        let x = (!ux >> 1) as i64;
        -x
    } else {
        let x = (ux >> 1) as i64;
        x
    })
}

/// `read_u8` reads a single byte from `r`.
fn read_u8<R>(r: &mut R) -> Result<u8, Error>
    where R: io::Read {

    r.bytes()
        .take_or_err(1, Error::EOF)
        .next()
        // take_or_err guarantees that we'll get an Error at worst.
        .unwrap()
}

/// `read_le_u16` reads 2 bytes as a little endian `u16` from 'r'
fn read_le_u16<R>(r: &mut R) -> Result<u16, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(2, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u16)
}

/// `read_le_u32` reads 4 bytes as a little endian `u32` from 'r'
fn read_le_u32<R>(r: &mut R) -> Result<u32, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(4, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u32)
}

/// `read_le_u64` reads 8 bytes as a little endian `u64` from 'r'
fn read_le_u64<R>(r: &mut R) -> Result<u64, Error>
    where R: io::Read {

    let itr = r.bytes().take_or_err(8, Error::EOF);

    result::fold(itr, 0, |so_far, next| (so_far << 8) + next as u64)
}

/// `read_i8` reads a single byte from `r`, as a 2's complement `i8`
fn read_i8<R>(r: &mut R) -> Result<i8, Error>
    where R: io::Read {

    Ok(try!(read_u8(r)) as i8)
}

/// `read_le_i16` reads 2 bytes as a little endian 2's complement `i16` from `r`.
fn read_le_i16<R>(r: &mut R) -> Result<i16, Error>
    where R: io::Read {

    Ok(try!(read_le_u16(r)) as i16)
}

/// `read_le_i32` reads 4 bytes as a little endian 2's complement `i32` from `r`.
fn read_le_i32<R>(r: &mut R) -> Result<i32, Error>
    where R: io::Read {

    Ok(try!(read_le_u32(r)) as i32)
}

/// `read_le_i64` reads 8 bytes as a little endian 2's complement `i64` from `r`.
fn read_le_i64<R>(r: &mut R) -> Result<i64, Error>
    where R: io::Read {

    Ok(try!(read_le_u64(r)) as i64)
}

/// `read_le_f32` reads 8 bytes as a little endian ieee-754 binary32 encoded `f32` from `r`.
fn read_le_f32<R>(r: &mut R) -> Result<f32, Error>
    where R: io::Read {

    let u = try!(read_le_u32(r));

    Ok(unsafe { mem::transmute(u) })
}

/// `read_le_f64` reads 8 bytes as a little endian ieee-754 binary64 encoded `f64` from `r`.
fn read_le_f64<R>(r: &mut R) -> Result<f64, Error>
    where R: io::Read {

    let u = try!(read_le_u64(r));

    Ok(unsafe { mem::transmute(u) })
}
<|endoftext|>


<commit_before>//! Functions and data-structures to load descriptor tables.

use core::mem::size_of;

use irq::IdtEntry;
use segmentation::SegmentDescriptor;

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[derive(Debug)]
#[repr(C, packed)]
pub struct DescriptorTablePointer<Entry> {
    /// Size of the DT.
    pub limit: u16,
    /// Pointer to the memory region containing the DT.
    pub base: *const Entry,
}

impl<T> DescriptorTablePointer<T> {
    fn new(slice: &[T]) -> Self {
        let len = slice.len() * size_of::<T>();
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: slice.as_ptr(),
            limit: len as u16,
        }
    }
}

impl DescriptorTablePointer<SegmentDescriptor> {
    pub fn new_gdtp(gdt: &[SegmentDescriptor]) -> Self {
        let mut p = Self::new(gdt);
        p.limit -= 1;
        p
    }
    pub fn new_ldtp(ldt: &[SegmentDescriptor]) -> Self {
        Self::new(ldt)
    }
}

impl DescriptorTablePointer<IdtEntry> {
    pub fn new_idtp(idt: &[IdtEntry]) -> Self {
        Self::new(idt)
    }
}

/// Load GDT table.
pub unsafe fn lgdt(gdt: &DescriptorTablePointer<SegmentDescriptor>) {
    asm!("lgdt ($0)" :: "r" (gdt) : "memory");
}

/// Load LDT table.
pub unsafe fn lldt(ldt: &DescriptorTablePointer<SegmentDescriptor>) {
    asm!("lldt ($0)" :: "r" (ldt) : "memory");
}

/// Load IDT table.
pub unsafe fn lidt(idt: &DescriptorTablePointer<IdtEntry>) {
    asm!("lidt ($0)" :: "r" (idt) : "memory");
}
<commit_msg>Don't require specific types for DescriptorTablePointer<commit_after>//! Functions and data-structures to load descriptor tables.

use core::mem::size_of;

use irq::IdtEntry;
use VirtualAddress;

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[derive(Debug)]
#[repr(C, packed)]
pub struct DescriptorTablePointer {
    /// Size of the DT.
    pub limit: u16,
    /// Address of the memory region containing the DT.
    pub base: VirtualAddress,
}

impl DescriptorTablePointer {
    fn new<T>(slice: &[T]) -> Self {
        let len = slice.len() * size_of::<T>();
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: VirtualAddress::from(slice.as_ptr() as usize),
            limit: len as u16,
        }
    }
}

impl DescriptorTablePointer {
    pub fn new_idtp(idt: &[IdtEntry]) -> Self {
        Self::new(idt)
    }
}

/// Load GDT table.
pub unsafe fn lgdt(gdt: &DescriptorTablePointer) {
    asm!("lgdt ($0)" :: "r" (gdt) : "memory");
}

/// Load LDT table.
pub unsafe fn lldt(ldt: &DescriptorTablePointer) {
    asm!("lldt ($0)" :: "r" (ldt) : "memory");
}

/// Load IDT table.
pub unsafe fn lidt(idt: &DescriptorTablePointer) {
    asm!("lidt ($0)" :: "r" (idt) : "memory");
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use controller::Reader;
use utils;

// Each line in the database file is a 'Record' that contains the following data to be read
// and serialized.
pub struct Record {
    // Unique (?) id given to each record.
    id: u64,
    // The payload of each record that is Base64 encoded and JSON serialized.
    payload: String,
    // Any necessary metedata needed to identify the record.
    // TODO Base64 encoded and JSON encoded?
    metadata: String,
}

pub struct Factory {
    reader: Reader,
}

pub type RecordResult<T, E> = Result<T, E>;

//TODO Add some factory traits here if necessary
pub trait RecordFactory {
    fn new(reader: Reader) -> Self;

    fn create(&self, data: String) -> RecordResult<Record, String>;
}

impl RecordFactory for Factory {
    fn new(reader: Reader) -> Factory {
        Factory {
            reader: reader,
        }
    }

    //TODO Remove the below flag when `create` is used
    #[allow(dead_code, unused_must_use, unused_variables)]
    fn create(&self, data: String) -> RecordResult<Record, String> {
        let vec_of_data = utils::string_slice(data);
        let id_num = FromStr::from_str(vec_of_data[0].as_slice());
        let id_value: u64 = match id_num {
            Some(value)     => value,
            None            => -1 // This is a failure value
        };

        Ok(Record {
            id: id_value,
            payload: vec_of_data[1].clone(),
            metadata: vec_of_data[2].clone(),
        })
    }
}

//TODO Remove the below flag when `create` is used
#[allow(dead_code, unused_must_use, unused_variables)]
fn create(data: String) -> RecordResult<Record, String> {
    let vec_of_data = utils::string_slice(data);
    let id_num = FromStr::from_str(vec_of_data[0].as_slice());
    let id_value: u64 = match id_num {
        Some(value)     => value,
        None            => -1 // This is a failure value
    };

    Ok(Record {
        id: id_value,
        payload: vec_of_data[1].clone(),
        metadata: vec_of_data[2].clone(),
    })

}

#[test]
fn test_create_record() {
    let input = String::from_str("1 payload metadata");
    let id_: u64 = 1;
    let expected = Record {
        id: id_,
        payload: String::from_str("payload"),
        metadata: String::from_str("metadata"),
    };
    let reader = Reader::new(Path::new("tests/base-test.txt"));
    let _factory: Factory = RecordFactory::new(reader);
    let output: Record = _factory.create(input).ok().expect("Parsing failed.");
    assert_eq!(expected.id, output.id);
    assert_eq!(expected.payload, output.payload);
    assert_eq!(expected.metadata, output.metadata);
}
<commit_msg>Added new test for non-implemented create_from_enc<commit_after>use std::str::FromStr;
use controller::Reader;
use utils;

// Each line in the database file is a 'Record' that contains the following data to be read
// and serialized.
pub struct Record {
    // Unique (?) id given to each record.
    id: u64,
    // The payload of each record that is Base64 encoded and JSON serialized.
    payload: String,
    // Any necessary metedata needed to identify the record.
    // TODO Base64 encoded and JSON encoded?
    metadata: String,
}

pub struct Factory {
    reader: Reader,
}

pub type RecordResult<T, E> = Result<T, E>;

//TODO Add some factory traits here if necessary
pub trait RecordFactory {
    fn new(reader: Reader) -> Self;

    fn create(&self, data: String) -> RecordResult<Record, String>;

    fn create_from_enc(&self, data: String) -> RecordResult<Record, String>;
}

impl RecordFactory for Factory {
    fn new(reader: Reader) -> Factory {
        Factory {
            reader: reader,
        }
    }

    //TODO Remove the below flag when `create` is used
    #[allow(dead_code, unused_must_use, unused_variables)]
    fn create(&self, data: String) -> RecordResult<Record, String> {
        let vec_of_data = utils::string_slice(data);
        let id_num = FromStr::from_str(vec_of_data[0].as_slice());
        let id_value: u64 = match id_num {
            Some(value)     => value,
            None            => -1 // This is a failure value
        };

        Ok(Record {
            id: id_value,
            payload: vec_of_data[1].clone(),
            metadata: vec_of_data[2].clone(),
        })
    }

    fn create_from_enc(&self, data: String) -> RecordResult<Record, String> {
        Ok(Record {
            id: 1,
            payload: String::from_str("Not implemented."),
            metadata: String::from_str("Not implemented."),
        })
    }
}

#[test]
fn test_create_record() {
    let input = String::from_str("1 payload metadata");
    let expected = Record {
        id: 1,
        payload: String::from_str("payload"),
        metadata: String::from_str("metadata"),
    };
    let reader = Reader::new(Path::new("tests/base-test.txt"));
    let factory: Factory = RecordFactory::new(reader);
    let output: Record = factory.create(input).ok().expect("Parsing failed.");
    assert_eq!(expected.id, output.id);
    assert_eq!(expected.payload, output.payload);
    assert_eq!(expected.metadata, output.metadata);
}

#[test]
fn test_create_from_encoded() {
    let input = String::from_str("5 cGF5bG9hZA== bWV0YWRhdGE=");
    let expected = Record {
        id: 5,
        payload: String::from_str("payload"),
        metadata: String::from_str("metadata"),
    };
    let reader = Reader::new(Path::new("tests/base-test.txt"));
    let factory: Factory = RecordFactory::new(reader);
    let output: Record = factory.create_from_enc(input).ok().expect("Parsing failed.");
    assert_eq!(expected.id, output.id);
    assert_eq!(expected.payload, output.payload);
    assert_eq!(expected.metadata, output.metadata);
}
<|endoftext|>


<commit_before>use std::ffi::CStr;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::net::{
    IpAddr,
    Ipv4Addr,
    Ipv6Addr,
};
use std::os::raw::{
    c_char,
    c_int,
};
use std::slice;
use std::str;

use c_ares_sys;
use c_types;
use itertools::Itertools;

use types::AddressFamily;
use utils::address_family;

#[derive(Debug)]
pub struct HostentOwned {
    inner: *mut c_types::hostent,
    phantom: PhantomData<c_types::hostent>,
}

impl HostentOwned {
    pub fn new(hostent: *mut c_types::hostent) -> HostentOwned {
        HostentOwned {
            inner: hostent,
            phantom: PhantomData,
        }
    }
}

impl Drop for HostentOwned {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_free_hostent(
                self.inner as *mut c_ares_sys::hostent);
        }
    }
}

#[derive(Clone, Copy)]
pub struct HostentBorrowed<'a> {
    inner: &'a c_types::hostent,
}

impl<'a> HostentBorrowed<'a> {
    pub fn new(hostent: &'a c_types::hostent) -> HostentBorrowed<'a> {
        HostentBorrowed {
            inner: hostent,
        }
    }
}

pub trait HasHostent {
    fn hostent(&self) -> &c_types::hostent;

    fn hostname(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr(self.hostent().h_name);
            str::from_utf8_unchecked(c_str.to_bytes())
        }
    }

    fn addresses(&self) -> HostAddressResultsIter {
        HostAddressResultsIter {
            family: address_family(self.hostent().h_addrtype as c_int),
            next: self.hostent().h_addr_list as *const *const _,
            phantom: PhantomData,
        }
    }

    fn aliases(&self) -> HostAliasResultsIter {
        HostAliasResultsIter {
            next: self.hostent().h_aliases as *const *const _,
            phantom: PhantomData,
        }
    }

    fn display(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "Hostname: {}, ", self.hostname()));
        let addresses = self.addresses().format_default(", ");
        try!(write!(fmt, "Addresses: [{}]", addresses));
        let aliases = self.aliases().format_default(", ");
        try!(write!(fmt, "Aliases: [{}]", aliases));
        Ok(())
    }
}

impl HasHostent for HostentOwned {
    fn hostent(&self) -> &c_types::hostent {
        unsafe { &*self.inner }
    }
}

impl<'a> HasHostent for HostentBorrowed<'a> {
    fn hostent(&self) -> &c_types::hostent {
        self.inner
    }
}

unsafe impl Send for HostentOwned { }
unsafe impl Sync for HostentOwned { }

unsafe impl<'a> Send for HostentBorrowed<'a> { }
unsafe impl<'a> Sync for HostentBorrowed<'a> { }

/// Iterator of `IpAddr`s.
#[derive(Clone, Copy, Debug)]
pub struct HostAddressResultsIter<'a> {
    family: Option<AddressFamily>,
    next: *const *const c_char,
    phantom: PhantomData<&'a c_types::hostent>,
}

// Get an IpAddr from a family and an array of bytes, as found in a `hostent`.
unsafe fn ip_address_from_bytes(
    family: AddressFamily,
    h_addr: *const u8) -> IpAddr {
    match family {
        AddressFamily::INET => {
            let source = slice::from_raw_parts(h_addr, 4);
            let mut bytes: [u8; 4] = mem::uninitialized();
            bytes.copy_from_slice(source);
            let ipv4 = Ipv4Addr::from(bytes);
            IpAddr::V4(ipv4)
        },
        AddressFamily::INET6 => {
            let source = slice::from_raw_parts(h_addr, 16);
            let mut bytes: [u8; 16] = mem::uninitialized();
            bytes.copy_from_slice(source);
            let ipv6 = Ipv6Addr::from(bytes);
            IpAddr::V6(ipv6)
        },
    }
}

impl<'a> Iterator for HostAddressResultsIter<'a> {
    type Item = IpAddr;
    fn next(&mut self) -> Option<Self::Item> {
        let h_addr = unsafe { *self.next };
        if h_addr.is_null() {
            None
        } else {
            unsafe {
                self.next = self.next.offset(1);
                self.family.map(|family| {
                    ip_address_from_bytes(family, h_addr as *const u8)
                })
            }
        }
    }
}

unsafe impl<'a> Send for HostAddressResultsIter<'a> { }
unsafe impl<'a> Sync for HostAddressResultsIter<'a> { }

/// Iterator of `&'a str`s.
#[derive(Clone, Copy, Debug)]
pub struct HostAliasResultsIter<'a> {
    next: *const *const c_char,
    phantom: PhantomData<&'a c_types::hostent>,
}

impl<'a> Iterator for HostAliasResultsIter<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<Self::Item> {
        let h_alias = unsafe { *self.next };
        if h_alias.is_null() {
            None
        } else {
            unsafe {
                self.next = self.next.offset(1);
                let c_str = CStr::from_ptr(h_alias);
                Some(str::from_utf8_unchecked(c_str.to_bytes()))
            }
        }
    }
}

unsafe impl<'a> Send for HostAliasResultsIter<'a> { }
unsafe impl<'a> Sync for HostAliasResultsIter<'a> { }
<commit_msg>Exorcise more Phantoms<commit_after>use std::ffi::CStr;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::net::{
    IpAddr,
    Ipv4Addr,
    Ipv6Addr,
};
use std::os::raw::{
    c_char,
    c_int,
};
use std::slice;
use std::str;

use c_ares_sys;
use c_types;
use itertools::Itertools;

use types::AddressFamily;
use utils::address_family;

#[derive(Debug)]
pub struct HostentOwned {
    inner: *mut c_types::hostent,
    phantom: PhantomData<c_types::hostent>,
}

impl HostentOwned {
    pub fn new(hostent: *mut c_types::hostent) -> HostentOwned {
        HostentOwned {
            inner: hostent,
            phantom: PhantomData,
        }
    }
}

impl Drop for HostentOwned {
    fn drop(&mut self) {
        unsafe {
            c_ares_sys::ares_free_hostent(
                self.inner as *mut c_ares_sys::hostent);
        }
    }
}

#[derive(Clone, Copy)]
pub struct HostentBorrowed<'a> {
    inner: &'a c_types::hostent,
}

impl<'a> HostentBorrowed<'a> {
    pub fn new(hostent: &'a c_types::hostent) -> HostentBorrowed<'a> {
        HostentBorrowed {
            inner: hostent,
        }
    }
}

pub trait HasHostent {
    fn hostent(&self) -> &c_types::hostent;

    fn hostname(&self) -> &str {
        unsafe {
            let c_str = CStr::from_ptr(self.hostent().h_name);
            str::from_utf8_unchecked(c_str.to_bytes())
        }
    }

    fn addresses(&self) -> HostAddressResultsIter {
        HostAddressResultsIter {
            family: address_family(self.hostent().h_addrtype as c_int),
            next: unsafe { &*(self.hostent().h_addr_list as *const _) },
        }
    }

    fn aliases(&self) -> HostAliasResultsIter {
        HostAliasResultsIter {
            next: unsafe { &*(self.hostent().h_aliases as *const _) },
        }
    }

    fn display(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(fmt, "Hostname: {}, ", self.hostname()));
        let addresses = self.addresses().format_default(", ");
        try!(write!(fmt, "Addresses: [{}]", addresses));
        let aliases = self.aliases().format_default(", ");
        try!(write!(fmt, "Aliases: [{}]", aliases));
        Ok(())
    }
}

impl HasHostent for HostentOwned {
    fn hostent(&self) -> &c_types::hostent {
        unsafe { &*self.inner }
    }
}

impl<'a> HasHostent for HostentBorrowed<'a> {
    fn hostent(&self) -> &c_types::hostent {
        self.inner
    }
}

unsafe impl Send for HostentOwned { }
unsafe impl Sync for HostentOwned { }

unsafe impl<'a> Send for HostentBorrowed<'a> { }
unsafe impl<'a> Sync for HostentBorrowed<'a> { }

/// Iterator of `IpAddr`s.
#[derive(Clone, Copy, Debug)]
pub struct HostAddressResultsIter<'a> {
    family: Option<AddressFamily>,
    next: &'a *const c_char,
}

// Get an IpAddr from a family and an array of bytes, as found in a `hostent`.
unsafe fn ip_address_from_bytes(
    family: AddressFamily,
    h_addr: *const u8) -> IpAddr {
    match family {
        AddressFamily::INET => {
            let source = slice::from_raw_parts(h_addr, 4);
            let mut bytes: [u8; 4] = mem::uninitialized();
            bytes.copy_from_slice(source);
            let ipv4 = Ipv4Addr::from(bytes);
            IpAddr::V4(ipv4)
        },
        AddressFamily::INET6 => {
            let source = slice::from_raw_parts(h_addr, 16);
            let mut bytes: [u8; 16] = mem::uninitialized();
            bytes.copy_from_slice(source);
            let ipv6 = Ipv6Addr::from(bytes);
            IpAddr::V6(ipv6)
        },
    }
}

impl<'a> Iterator for HostAddressResultsIter<'a> {
    type Item = IpAddr;
    fn next(&mut self) -> Option<Self::Item> {
        let h_addr = *self.next;
        if h_addr.is_null() {
            None
        } else {
            unsafe {
                self.next = &*(self.next as *const _).offset(1);
                self.family.map(|family| {
                    ip_address_from_bytes(family, h_addr as *const u8)
                })
            }
        }
    }
}

unsafe impl<'a> Send for HostAddressResultsIter<'a> { }
unsafe impl<'a> Sync for HostAddressResultsIter<'a> { }

/// Iterator of `&'a str`s.
#[derive(Clone, Copy, Debug)]
pub struct HostAliasResultsIter<'a> {
    next: &'a *const c_char,
}

impl<'a> Iterator for HostAliasResultsIter<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<Self::Item> {
        let h_alias = *self.next;
        if h_alias.is_null() {
            None
        } else {
            unsafe {
                self.next = &*(self.next as *const _).offset(1);
                let c_str = CStr::from_ptr(h_alias);
                Some(str::from_utf8_unchecked(c_str.to_bytes()))
            }
        }
    }
}

unsafe impl<'a> Send for HostAliasResultsIter<'a> { }
unsafe impl<'a> Sync for HostAliasResultsIter<'a> { }
<|endoftext|>