<commit_before>use codec::{
    eyre::Result,
    stencila_schema::{Node, Null},
    utils::vec_string,
    Codec, CodecTrait, DecodeOptions, EncodeOptions,
};
use node_coerce::coerce;

mod encode;
pub use encode::ToTxt;

/// A codec for plain text
///
/// This codec is intentionally lossy but is useful for when a
/// plain text representation of a node is needed.
pub struct TxtCodec {}

impl CodecTrait for TxtCodec {
    fn spec() -> Codec {
        Codec {
            formats: vec_string!["txt"],
            root_types: vec_string!["*"],
            from_string: true,
            from_path: true,
            to_string: true,
            to_path: true,
            ..Default::default()
        }
    }

    /// Decode plain text to a `Node`
    ///
    /// Attempts to decode as a JSON5 string first, falling back
    /// to unquoting a string, falling back to just returning a
    /// string node.
    ///
    /// Uses JSON5 over JSON, as a more permissive standard (e.g. strings can
    /// be single quoted) and thus able to deal with representations of values
    /// that are not strictly JSON (e.g. a Python dict repr).
    ///
    /// This function is useful in contexts where some text may or may not
    /// represent a boolean, number or some other JSON object, for example
    /// the output of a Jupyter code cell where a `dict` has a representation
    /// which can be parsed as a JSON object.
    fn from_str(str: &str, _options: Option<DecodeOptions>) -> Result<Node> {
        match str.trim() {
            "true" | "TRUE" | "True" => return Ok(Node::Boolean(true)),
            "false" | "FALSE" | "False" => return Ok(Node::Boolean(false)),
            "null" | "NULL" | "Null" => return Ok(Node::Null(Null {})),
            _ => (),
        };

        if let Ok(node) = json5::from_str(str) {
            return coerce(node, None);
        }

        Ok(Node::String(str.to_string()))
    }

    /// Encode a `Node` to plain text
    ///
    /// The only structure added is placing two newlines after each `BlockContent`
    /// node. e.g. paragraphs, code blocks
    fn to_string(node: &Node, _options: Option<EncodeOptions>) -> Result<String> {
        Ok(node.to_txt().trim().to_string())
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use super::*;
    use codec::{eyre::bail, stencila_schema::Primitive};
    use test_utils::assert_json_eq;

    #[test]
    fn booleans() -> Result<()> {
        assert!(matches!(
            TxtCodec::from_str("true", None)?,
            Node::Boolean(true)
        ));
        assert!(matches!(
            TxtCodec::from_str("TRUE", None)?,
            Node::Boolean(true)
        ));
        assert!(matches!(
            TxtCodec::from_str("  True  ", None)?,
            Node::Boolean(true)
        ));
        Ok(())
    }

    #[test]
    fn nulls() -> Result<()> {
        assert!(matches!(
            TxtCodec::from_str("null", None)?,
            Node::Null(Null {})
        ));
        assert!(matches!(
            TxtCodec::from_str("NULL", None)?,
            Node::Null(Null {})
        ));
        assert!(matches!(
            TxtCodec::from_str("  Null  ", None)?,
            Node::Null(Null {})
        ));
        Ok(())
    }

    #[test]
    #[allow(clippy::float_cmp)]
    fn numbers() -> Result<()> {
        assert!(matches!(TxtCodec::from_str("1", None)?, Node::Integer(1)));
        match TxtCodec::from_str("1.23", None)? {
            Node::Number(value) => assert_eq!(value, 1.23),
            _ => bail!("Wrong type {:?}",),
        }
        Ok(())
    }

    #[test]
    fn objects_arrays() -> Result<()> {
        let mut map = BTreeMap::new();
        map.insert("a".to_string(), Primitive::Integer(1));
        assert_json_eq!(
            TxtCodec::from_str(r#"{"a": 1}"#, None)?,
            Primitive::Object(map)
        );
        assert_json_eq!(
            TxtCodec::from_str(r#"[1]"#, None)?,
            Node::Array(vec![Primitive::Integer(1)])
        );
        Ok(())
    }

    #[test]
    fn strings() -> Result<()> {
        match TxtCodec::from_str("not valid json", None)? {
            Node::String(value) => assert_eq!(value, "not valid json"),
            _ => bail!("Wrong type {:?}",),
        }
        Ok(())
    }
}
<commit_msg>chore(Txt codec): Update spec<commit_after>use codec::{
    eyre::Result,
    stencila_schema::{Node, Null},
    utils::vec_string,
    Codec, CodecTrait, DecodeOptions, EncodeOptions,
};
use node_coerce::coerce;

mod encode;
pub use encode::ToTxt;

/// A codec for plain text
///
/// This codec is intentionally lossy but is useful for when a
/// plain text representation of a node is needed.
pub struct TxtCodec {}

impl CodecTrait for TxtCodec {
    fn spec() -> Codec {
        Codec {
            status: "beta".to_string(),
            formats: vec_string!["txt"],
            root_types: vec_string!["*"],
            ..Default::default()
        }
    }

    /// Decode plain text to a `Node`
    ///
    /// Attempts to decode as a JSON5 string first, falling back
    /// to unquoting a string, falling back to just returning a
    /// string node.
    ///
    /// Uses JSON5 over JSON, as a more permissive standard (e.g. strings can
    /// be single quoted) and thus able to deal with representations of values
    /// that are not strictly JSON (e.g. a Python dict repr).
    ///
    /// This function is useful in contexts where some text may or may not
    /// represent a boolean, number or some other JSON object, for example
    /// the output of a Jupyter code cell where a `dict` has a representation
    /// which can be parsed as a JSON object.
    fn from_str(str: &str, _options: Option<DecodeOptions>) -> Result<Node> {
        match str.trim() {
            "true" | "TRUE" | "True" => return Ok(Node::Boolean(true)),
            "false" | "FALSE" | "False" => return Ok(Node::Boolean(false)),
            "null" | "NULL" | "Null" => return Ok(Node::Null(Null {})),
            _ => (),
        };

        if let Ok(node) = json5::from_str(str) {
            return coerce(node, None);
        }

        Ok(Node::String(str.to_string()))
    }

    /// Encode a `Node` to plain text
    ///
    /// The only structure added is placing two newlines after each `BlockContent`
    /// node. e.g. paragraphs, code blocks
    fn to_string(node: &Node, _options: Option<EncodeOptions>) -> Result<String> {
        Ok(node.to_txt().trim().to_string())
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use super::*;
    use codec::{eyre::bail, stencila_schema::Primitive};
    use test_utils::assert_json_eq;

    #[test]
    fn booleans() -> Result<()> {
        assert!(matches!(
            TxtCodec::from_str("true", None)?,
            Node::Boolean(true)
        ));
        assert!(matches!(
            TxtCodec::from_str("TRUE", None)?,
            Node::Boolean(true)
        ));
        assert!(matches!(
            TxtCodec::from_str("  True  ", None)?,
            Node::Boolean(true)
        ));
        Ok(())
    }

    #[test]
    fn nulls() -> Result<()> {
        assert!(matches!(
            TxtCodec::from_str("null", None)?,
            Node::Null(Null {})
        ));
        assert!(matches!(
            TxtCodec::from_str("NULL", None)?,
            Node::Null(Null {})
        ));
        assert!(matches!(
            TxtCodec::from_str("  Null  ", None)?,
            Node::Null(Null {})
        ));
        Ok(())
    }

    #[test]
    #[allow(clippy::float_cmp)]
    fn numbers() -> Result<()> {
        assert!(matches!(TxtCodec::from_str("1", None)?, Node::Integer(1)));
        match TxtCodec::from_str("1.23", None)? {
            Node::Number(value) => assert_eq!(value, 1.23),
            _ => bail!("Wrong type {:?}",),
        }
        Ok(())
    }

    #[test]
    fn objects_arrays() -> Result<()> {
        let mut map = BTreeMap::new();
        map.insert("a".to_string(), Primitive::Integer(1));
        assert_json_eq!(
            TxtCodec::from_str(r#"{"a": 1}"#, None)?,
            Primitive::Object(map)
        );
        assert_json_eq!(
            TxtCodec::from_str(r#"[1]"#, None)?,
            Node::Array(vec![Primitive::Integer(1)])
        );
        Ok(())
    }

    #[test]
    fn strings() -> Result<()> {
        match TxtCodec::from_str("not valid json", None)? {
            Node::String(value) => assert_eq!(value, "not valid json"),
            _ => bail!("Wrong type {:?}",),
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::utils::{get_trait_def_id, paths, span_lint, span_lint_and_help};
use if_chain::if_chain;
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::{GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{BytePos, Span};

declare_clippy_lint! {
    /// **What it does:** Checks for functions that expect closures of type
    /// Fn(...) -> Ord where the implemented closure returns the unit type.
    /// The lint also suggests to remove the semi-colon at the end of the statement if present.
    ///
    /// **Why is this bad?** Likely, returning the unit type is unintentional, and
    /// could simply be caused by an extra semi-colon. Since () implements Ord
    /// it doesn't cause a compilation error.
    /// This is the same reasoning behind the unit_cmp lint.
    ///
    /// **Known problems:** If returning unit is intentional, then there is no
    /// way of specifying this without triggering needless_return lint
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let mut twins = vec!((1,1), (2,2));
    /// twins.sort_by_key(|x| { x.1; });
    /// ```
    pub UNIT_RETURN_EXPECTING_ORD,
    correctness,
    "fn arguments of type Fn(...) -> Ord returning the unit type ()."
}

declare_lint_pass!(UnitReturnExpectingOrd => [UNIT_RETURN_EXPECTING_ORD]);

fn get_trait_predicates_for_trait_id<'tcx>(
    cx: &LateContext<'tcx>,
    generics: GenericPredicates<'tcx>,
    trait_id: Option<DefId>,
) -> Vec<TraitPredicate<'tcx>> {
    let mut preds = Vec::new();
    for (pred, _) in generics.predicates {
        if_chain! {
            if let PredicateKind::Trait(poly_trait_pred, _) = pred.kind();
            let trait_pred = cx.tcx.erase_late_bound_regions(&poly_trait_pred);
            if let Some(trait_def_id) = trait_id;
            if trait_def_id == trait_pred.trait_ref.def_id;
            then {
                preds.push(trait_pred);
            }
        }
    }
    preds
}

fn get_projection_pred<'tcx>(
    cx: &LateContext<'tcx>,
    generics: GenericPredicates<'tcx>,
    pred: TraitPredicate<'tcx>,
) -> Option<ProjectionPredicate<'tcx>> {
    generics.predicates.iter().find_map(|(proj_pred, _)| {
        if let PredicateKind::Projection(proj_pred) = proj_pred.kind() {
            let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred);
            if projection_pred.projection_ty.substs == pred.trait_ref.substs {
                return Some(projection_pred);
            }
        }
        None
    })
}

fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Vec<(usize, String)> {
    let mut args_to_check = Vec::new();
    if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
        let fn_sig = cx.tcx.fn_sig(def_id);
        let generics = cx.tcx.predicates_of(def_id);
        let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait());
        let ord_preds = get_trait_predicates_for_trait_id(cx, generics, get_trait_def_id(cx, &paths::ORD));
        let partial_ord_preds =
            get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().partial_ord_trait());
        // Trying to call erase_late_bound_regions on fn_sig.inputs() gives the following error
        // The trait `rustc::ty::TypeFoldable<'_>` is not implemented for `&[&rustc::ty::TyS<'_>]`
        let inputs_output = cx.tcx.erase_late_bound_regions(&fn_sig.inputs_and_output());
        inputs_output
            .iter()
            .rev()
            .skip(1)
            .rev()
            .enumerate()
            .for_each(|(i, inp)| {
                for trait_pred in &fn_mut_preds {
                    if_chain! {
                        if trait_pred.self_ty() == inp;
                        if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
                        then {
                            if ord_preds.iter().any(|ord| ord.self_ty() == return_ty_pred.ty) {
                                args_to_check.push((i, "Ord".to_string()));
                            } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.ty) {
                                args_to_check.push((i, "PartialOrd".to_string()));
                            }
                        }
                    }
                }
            });
    }
    args_to_check
}

fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option<Span>)> {
    if_chain! {
        if let ExprKind::Closure(_, _fn_decl, body_id, span, _) = arg.kind;
        if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind;
        let ret_ty = substs.as_closure().sig().output();
        let ty = cx.tcx.erase_late_bound_regions(&ret_ty);
        if ty.is_unit();
        then {
            if_chain! {
                let body = cx.tcx.hir().body(body_id);
                if let ExprKind::Block(block, _) = body.value.kind;
                if block.expr.is_none();
                if let Some(stmt) = block.stmts.last();
                if let StmtKind::Semi(_) = stmt.kind;
                then {
                    let data = stmt.span.data();
                    // Make a span out of the semicolon for the help message
                    Some((span, Some(Span::new(data.hi-BytePos(1), data.hi, data.ctxt))))
                } else {
                    Some((span, None))
                }
            }
        } else {
            None
        }
    }
}

impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
        if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
            let arg_indices = get_args_to_check(cx, expr);
            for (i, trait_name) in arg_indices {
                if i < args.len() {
                    match check_arg(cx, &args[i]) {
                        Some((span, None)) => {
                            span_lint(
                                cx,
                                UNIT_RETURN_EXPECTING_ORD,
                                span,
                                &format!(
                                    "this closure returns \
                                   the unit type which also implements {}",
                                    trait_name
                                ),
                            );
                        },
                        Some((span, Some(last_semi))) => {
                            span_lint_and_help(
                                cx,
                                UNIT_RETURN_EXPECTING_ORD,
                                span,
                                &format!(
                                    "this closure returns \
                                   the unit type which also implements {}",
                                    trait_name
                                ),
                                Some(last_semi),
                                &"probably caused by this trailing semicolon".to_string(),
                            );
                        },
                        None => {},
                    }
                }
            }
        }
    }
}
<commit_msg>clippy<commit_after>use crate::utils::{get_trait_def_id, paths, span_lint, span_lint_and_help};
use if_chain::if_chain;
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::{GenericPredicates, PredicateAtom, ProjectionPredicate, TraitPredicate};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{BytePos, Span};

declare_clippy_lint! {
    /// **What it does:** Checks for functions that expect closures of type
    /// Fn(...) -> Ord where the implemented closure returns the unit type.
    /// The lint also suggests to remove the semi-colon at the end of the statement if present.
    ///
    /// **Why is this bad?** Likely, returning the unit type is unintentional, and
    /// could simply be caused by an extra semi-colon. Since () implements Ord
    /// it doesn't cause a compilation error.
    /// This is the same reasoning behind the unit_cmp lint.
    ///
    /// **Known problems:** If returning unit is intentional, then there is no
    /// way of specifying this without triggering needless_return lint
    ///
    /// **Example:**
    ///
    /// ```rust
    /// let mut twins = vec!((1,1), (2,2));
    /// twins.sort_by_key(|x| { x.1; });
    /// ```
    pub UNIT_RETURN_EXPECTING_ORD,
    correctness,
    "fn arguments of type Fn(...) -> Ord returning the unit type ()."
}

declare_lint_pass!(UnitReturnExpectingOrd => [UNIT_RETURN_EXPECTING_ORD]);

fn get_trait_predicates_for_trait_id<'tcx>(
    cx: &LateContext<'tcx>,
    generics: GenericPredicates<'tcx>,
    trait_id: Option<DefId>,
) -> Vec<TraitPredicate<'tcx>> {
    let mut preds = Vec::new();
    for (pred, _) in generics.predicates {
        if_chain! {
            if let PredicateAtom::Trait(poly_trait_pred, _) = pred.skip_binders();
            let trait_pred = cx.tcx.erase_late_bound_regions(&ty::Binder::bind(poly_trait_pred));
            if let Some(trait_def_id) = trait_id;
            if trait_def_id == trait_pred.trait_ref.def_id;
            then {
                preds.push(trait_pred);
            }
        }
    }
    preds
}

fn get_projection_pred<'tcx>(
    cx: &LateContext<'tcx>,
    generics: GenericPredicates<'tcx>,
    pred: TraitPredicate<'tcx>,
) -> Option<ProjectionPredicate<'tcx>> {
    generics.predicates.iter().find_map(|(proj_pred, _)| {
        if let ty::PredicateAtom::Projection(proj_pred) = proj_pred.skip_binders() {
            let projection_pred = cx.tcx.erase_late_bound_regions(&ty::Binder::bind(proj_pred));
            if projection_pred.projection_ty.substs == pred.trait_ref.substs {
                return Some(projection_pred);
            }
        }
        None
    })
}

fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Vec<(usize, String)> {
    let mut args_to_check = Vec::new();
    if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
        let fn_sig = cx.tcx.fn_sig(def_id);
        let generics = cx.tcx.predicates_of(def_id);
        let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait());
        let ord_preds = get_trait_predicates_for_trait_id(cx, generics, get_trait_def_id(cx, &paths::ORD));
        let partial_ord_preds =
            get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().partial_ord_trait());
        // Trying to call erase_late_bound_regions on fn_sig.inputs() gives the following error
        // The trait `rustc::ty::TypeFoldable<'_>` is not implemented for `&[&rustc::ty::TyS<'_>]`
        let inputs_output = cx.tcx.erase_late_bound_regions(&fn_sig.inputs_and_output());
        inputs_output
            .iter()
            .rev()
            .skip(1)
            .rev()
            .enumerate()
            .for_each(|(i, inp)| {
                for trait_pred in &fn_mut_preds {
                    if_chain! {
                        if trait_pred.self_ty() == inp;
                        if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
                        then {
                            if ord_preds.iter().any(|ord| ord.self_ty() == return_ty_pred.ty) {
                                args_to_check.push((i, "Ord".to_string()));
                            } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.ty) {
                                args_to_check.push((i, "PartialOrd".to_string()));
                            }
                        }
                    }
                }
            });
    }
    args_to_check
}

fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option<Span>)> {
    if_chain! {
        if let ExprKind::Closure(_, _fn_decl, body_id, span, _) = arg.kind;
        if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind;
        let ret_ty = substs.as_closure().sig().output();
        let ty = cx.tcx.erase_late_bound_regions(&ret_ty);
        if ty.is_unit();
        then {
            if_chain! {
                let body = cx.tcx.hir().body(body_id);
                if let ExprKind::Block(block, _) = body.value.kind;
                if block.expr.is_none();
                if let Some(stmt) = block.stmts.last();
                if let StmtKind::Semi(_) = stmt.kind;
                then {
                    let data = stmt.span.data();
                    // Make a span out of the semicolon for the help message
                    Some((span, Some(Span::new(data.hi-BytePos(1), data.hi, data.ctxt))))
                } else {
                    Some((span, None))
                }
            }
        } else {
            None
        }
    }
}

impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
        if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
            let arg_indices = get_args_to_check(cx, expr);
            for (i, trait_name) in arg_indices {
                if i < args.len() {
                    match check_arg(cx, &args[i]) {
                        Some((span, None)) => {
                            span_lint(
                                cx,
                                UNIT_RETURN_EXPECTING_ORD,
                                span,
                                &format!(
                                    "this closure returns \
                                   the unit type which also implements {}",
                                    trait_name
                                ),
                            );
                        },
                        Some((span, Some(last_semi))) => {
                            span_lint_and_help(
                                cx,
                                UNIT_RETURN_EXPECTING_ORD,
                                span,
                                &format!(
                                    "this closure returns \
                                   the unit type which also implements {}",
                                    trait_name
                                ),
                                Some(last_semi),
                                &"probably caused by this trailing semicolon".to_string(),
                            );
                        },
                        None => {},
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>pub mod ingest;
pub mod demosaic;
pub mod level;
pub mod colorspaces;
pub mod curves;
pub mod gamma;

use decoders::Image;

#[inline] pub fn fcol (img: &Image, row: usize, col: usize) -> usize {
//  let filter: [usize; 256] = [
//    2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0,
//    0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2,
//    2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3,
//    0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1,
//    3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0,
//    2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1,
//    2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1,
//    1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3,
//    2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3,
//    1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2,
//    0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2,
//    2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0,
//    1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0,
//    0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1,
//    2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2,
//    0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3
//  ];

//  match img.dcraw_filters {
//    1 => filter[(row&15)*img.width+(col&15)] as usize,
//    //9 => img.xtrans_filters[((row+600) % 6)*width + ((col+600) % 6)],
//    _ =>
(img.dcraw_filters >> (((row << 1 & 14) + (col & 1) ) << 1) & 3) as usize
//  }
}

pub fn simple_decode (img: &Image) -> Vec<f32> {
  // Start with a 1 channel f32 (pre-demosaic)
  let channel1 = ingest::float(img);
  // Demosaic into 4 channel f32 (RGB or RGBE)
  let mut channel4 = demosaic::ppg(img, &channel1);
  level::level_and_balance(img, &mut channel4);
  // From now on we are in 3 channel f32 (RGB or Lab)
  let mut channel3 = colorspaces::camera_to_lab(img, &channel4);
  curves::base(img, &mut channel3);
  colorspaces::lab_to_rec709(img, &mut channel3);
  gamma::gamma(img, &mut channel3);

  channel3
}
<commit_msg>imageops: add some timing for the iops<commit_after>pub mod ingest;
pub mod demosaic;
pub mod level;
pub mod colorspaces;
pub mod curves;
pub mod gamma;

use decoders::Image;

extern crate time;

#[inline] pub fn fcol (img: &Image, row: usize, col: usize) -> usize {
//  let filter: [usize; 256] = [
//    2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0,
//    0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2,
//    2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3,
//    0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1,
//    3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0,
//    2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1,
//    2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1,
//    1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3,
//    2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3,
//    1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2,
//    0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2,
//    2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0,
//    1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0,
//    0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1,
//    2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2,
//    0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3
//  ];

//  match img.dcraw_filters {
//    1 => filter[(row&15)*img.width+(col&15)] as usize,
//    //9 => img.xtrans_filters[((row+600) % 6)*width + ((col+600) % 6)],
//    _ =>
(img.dcraw_filters >> (((row << 1 & 14) + (col & 1) ) << 1) & 3) as usize
//  }
}

fn do_timing<O, F: FnMut() -> O>(name: &str, mut closure: F) -> O {
  let from_time = time::precise_time_ns();
  let ret = closure();
  let to_time = time::precise_time_ns();
  println!("{} ms for '{}'", (to_time - from_time)/1000000, name);

  ret
}

pub fn simple_decode (img: &Image) -> Vec<f32> {
  // Start with a 1 channel f32 (pre-demosaic)
  let channel1 = do_timing("ingest", ||ingest::float(img));
  // Demosaic into 4 channel f32 (RGB or RGBE)
  let mut channel4 = do_timing("demosaic", ||demosaic::ppg(img, &channel1));

  do_timing("level_and_balance", || { level::level_and_balance(img, &mut channel4) });
  // From now on we are in 3 channel f32 (RGB or Lab)
  let mut channel3 = do_timing("camera_to_lab", ||colorspaces::camera_to_lab(img, &channel4));
  do_timing("base_curve", ||curves::base(img, &mut channel3));
  do_timing("lab_to_rec709", ||colorspaces::lab_to_rec709(img, &mut channel3));
  do_timing("gamma", ||gamma::gamma(img, &mut channel3));

  channel3
}
<|endoftext|>


<commit_before>use super::ssz::decode::{
    decode_length,
    Decodable,
};
use super::utils::hash::canonical_hash;
use super::block::{
    MIN_SSZ_BLOCK_LENGTH,
    MAX_SSZ_BLOCK_LENGTH,
};

#[derive(Debug, PartialEq)]
pub enum BlockValidatorError {
    TooShort,
    TooLong,
    NoAttestationRecords,
    BadPowHash,
    SlotTooLow,
    SlotTooHigh,
}

const LENGTH_BYTES: usize = 4;

/// Allows for reading of block values directly from serialized
/// ssz bytes.
#[derive(Debug, PartialEq)]
pub struct SszBlock<'a> {
    ssz: &'a [u8],
    attestation_len: usize,
    pub len: usize,
}

impl<'a> SszBlock<'a> {
    pub fn from_slice(vec: &'a [u8])
        -> Result<Self, BlockValidatorError>
    {
        let ssz = &vec[..];
        let len = vec.len();
        /*
         * Ensure the SSZ is long enough to be a block.
         */
        if len < MIN_SSZ_BLOCK_LENGTH {
            return Err(BlockValidatorError::TooShort);
        }
        /*
         * Ensure the SSZ slice isn't longer than is possible for a block.
         */
        if len > MAX_SSZ_BLOCK_LENGTH {
            return Err(BlockValidatorError::TooLong);
        }
        /*
         * Determine how many bytes are used to store attestation records
         * and ensure that length is enough to store at least one attestation
         * record.
         */
        let attestation_len = decode_length(ssz, 72, LENGTH_BYTES)
            .map_err(|_| BlockValidatorError::TooShort)?;
        if len < (76 + attestation_len + 96) {
            return Err(BlockValidatorError::TooShort);
        }
        Ok(Self{
            ssz,
            attestation_len,
            len,
        })
    }

    pub fn block_hash(&self) -> Vec<u8> {
        canonical_hash(self.ssz)
    }

    pub fn parent_hash(&self) -> &[u8] {
        &self.ssz[0..32]
    }

    pub fn slot_number(&self) -> u64 {
        u64::ssz_decode(&self.ssz, 32).unwrap().0
    }

    pub fn randao_reveal(&self) -> &[u8] {
        &self.ssz[40..72]
    }

    pub fn attestations(&self) -> &[u8] {
        let start = 72 + LENGTH_BYTES;
        &self.ssz[start..(start + self.attestation_len)]
    }

    pub fn pow_chain_ref(&self) -> &[u8] {
        &self.ssz[(self.len - 96)..(self.len - 64)]
    }

    pub fn act_state_root(&self) -> &[u8] {
        &self.ssz[(self.len - 64)..(self.len - 32)]
    }

    pub fn cry_state_root(&self) -> &[u8] {
        &self.ssz[(self.len - 32)..(self.len)]
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::block::Block;
    use super::super::attestation_record::AttestationRecord;
    use super::super::ssz::SszStream;

    fn get_block_ssz(b: &Block) -> Vec<u8> {
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(b);
        ssz_stream.drain()
    }

    #[test]
    fn test_ssz_block_zero_attestation_records() {
        let mut b = Block::zero();
        b.attestations = vec![];
        let ssz = get_block_ssz(&b);

        assert_eq!(
            SszBlock::from_slice(&ssz[..]),
            Err(BlockValidatorError::NoAttestationRecords)
        );
    }

    #[test]
    fn test_ssz_block_single_attestation_record() {
        let mut b = Block::zero();
        b.attestations = vec![AttestationRecord::zero()];
        let ssz = get_block_ssz(&b);

        assert_eq!(
            SszBlock::from_slice(&ssz[..]),
            Err(BlockValidatorError::NoAttestationRecords)
        );
    }
}
<commit_msg>Half update some ssz indexes for ssz_block<commit_after>use super::ssz::decode::{
    decode_length,
    Decodable,
};
use super::utils::hash::canonical_hash;
use super::block::{
    MIN_SSZ_BLOCK_LENGTH,
    MAX_SSZ_BLOCK_LENGTH,
};

#[derive(Debug, PartialEq)]
pub enum BlockValidatorError {
    TooShort,
    TooLong,
    NoAttestationRecords,
    BadPowHash,
    SlotTooLow,
    SlotTooHigh,
}

const LENGTH_BYTES: usize = 4;

/// Allows for reading of block values directly from serialized
/// ssz bytes.
#[derive(Debug, PartialEq)]
pub struct SszBlock<'a> {
    ssz: &'a [u8],
    attestation_len: usize,
    pub len: usize,
}

impl<'a> SszBlock<'a> {
    pub fn from_slice(vec: &'a [u8])
        -> Result<Self, BlockValidatorError>
    {
        let ssz = &vec[..];
        let len = vec.len();
        /*
         * Ensure the SSZ is long enough to be a block.
         */
        if len < MIN_SSZ_BLOCK_LENGTH {
            return Err(BlockValidatorError::TooShort);
        }
        /*
         * Ensure the SSZ slice isn't longer than is possible for a block.
         */
        if len > MAX_SSZ_BLOCK_LENGTH {
            return Err(BlockValidatorError::TooLong);
        }
        /*
         * Determine how many bytes are used to store attestation records
         * and ensure that length is enough to store at least one attestation
         * record.
         */
        let attestation_len = decode_length(ssz, 80, LENGTH_BYTES)
            .map_err(|_| BlockValidatorError::TooShort)?;
        if len < (76 + attestation_len + 96) {
            return Err(BlockValidatorError::TooShort);
        }
        Ok(Self{
            ssz,
            attestation_len,
            len,
        })
    }

    pub fn block_hash(&self) -> Vec<u8> {
        canonical_hash(self.ssz)
    }

    pub fn parent_hash(&self) -> &[u8] {
        &self.ssz[5..37]
    }

    pub fn slot_number(&self) -> u64 {
        u64::ssz_decode(&self.ssz, 32).unwrap().0
    }

    pub fn randao_reveal(&self) -> &[u8] {
        &self.ssz[40..72]
    }

    pub fn attestations(&self) -> &[u8] {
        let start = 72 + LENGTH_BYTES;
        &self.ssz[start..(start + self.attestation_len)]
    }

    pub fn pow_chain_ref(&self) -> &[u8] {
        &self.ssz[(self.len - 96)..(self.len - 64)]
    }

    pub fn act_state_root(&self) -> &[u8] {
        &self.ssz[(self.len - 64)..(self.len - 32)]
    }

    pub fn cry_state_root(&self) -> &[u8] {
        &self.ssz[(self.len - 32)..(self.len)]
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::block::Block;
    use super::super::attestation_record::AttestationRecord;
    use super::super::ssz::SszStream;

    fn get_block_ssz(b: &Block) -> Vec<u8> {
        let mut ssz_stream = SszStream::new();
        ssz_stream.append(b);
        ssz_stream.drain()
    }

    #[test]
    fn test_ssz_block_zero_attestation_records() {
        let mut b = Block::zero();
        b.attestations = vec![];
        let ssz = get_block_ssz(&b);

        assert_eq!(
            SszBlock::from_slice(&ssz[..]),
            Err(BlockValidatorError::NoAttestationRecords)
        );
    }

    #[test]
    fn test_ssz_block_single_attestation_record() {
        let mut b = Block::zero();
        b.attestations = vec![AttestationRecord::zero()];
        let ssz = get_block_ssz(&b);

        assert_eq!(
            SszBlock::from_slice(&ssz[..]),
            Err(BlockValidatorError::NoAttestationRecords)
        );
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;

#[derive(Debug)]
pub enum Command {
    Nick,
    User,
    Join,
    Quit,
    Ping,
    Mode,
    Pong,
    Pass,
    Privmsg,
    Numeric(u32),
    Unknown(String)
}

impl Command {
    pub fn as_string(&self) -> String {
        match self {
            &Command::Nick => "NICK".to_string(),
            &Command::Join => "JOIN".to_string(),
            &Command::Pong => "PONG".to_string(),
            &Command::Privmsg => "PRIVMSG".to_string(),
            &Command::User => "USER".to_string(),
            &Command::Quit => "QUIT".to_string(),
            &Command::Ping => "PING".to_string(),
            &Command::Mode => "MODE".to_string(),
            &Command::Pass => "PASS".to_string(),
            &Command::Numeric(n)=> format!("{:0>3}", n),
            &Command::Unknown(ref s) => s.clone()
        }
    }
}

impl Message {
    pub fn to_string(&self) -> String {
        let mut ret = String::new();
        match self.prefix {
            Some(ref pfx) => {
                ret.push(':');
                ret.push_str(pfx.trim());
                ret.push(' ');
            },
            None => ()
        };
        ret.push_str(self.command.as_string().trim());
        for ref arg in self.args.iter() {
            ret.push(' ');
            ret.push_str(arg.trim());
        }

        match self.suffix {
            Some(ref sfx) => {
                ret.push_str(" :");
                ret.push_str(sfx.trim());
            },
            None => ()
        };

        return ret;
    }

    fn split_parts(line: &str) -> (Option<String>, &str, Option<String>) {
        let mut prefix_end = 0;
        let mut args_end = 0;
        if line.chars().nth(0).unwrap() == ':' {
            for c in line[1..].chars() {
                prefix_end += 1;
                if c == ' ' {
                    break
                }
            }
        }

        let mut found_space = false;
        for c in line[prefix_end..].chars() {
            if c == ' ' {
                found_space = true;
            } else if c == ':' && found_space {
                args_end -= 1;
                break
            } else {
                found_space = false;
            }
            args_end += 1;
        }

        let prefix = match prefix_end {
            0 => None,
            _ => Some(line[1..prefix_end].to_string())
        };
        let args = &line[prefix_end..args_end].trim();
        let len = line.len();
        let suffix = if args_end == len {
            None
        } else {
            Some(line[args_end+2..].to_string())
        };

        (prefix, args, suffix)
    }

    pub fn from_str(line: &str) -> Self {
        let parts = Self::split_parts(line.trim());
        let split: Vec<&str> = parts.1.split(" ").collect();
        let mut args = Vec::new();
        for s in split[1..].iter() {
            args.push(s.to_string());
        }
        let parsedCommand: Result<Command, Command> = split[0].parse();
        Message{
            prefix: parts.0,
            command: parsedCommand.ok().unwrap(),
            args: args,
            suffix: parts.2
        }
    }
}

impl From<Command> for Message {
    fn from(c: Command) -> Message {
        Message {
            prefix: None,
            command: c,
            args: vec![],
            suffix: None
        }
    }
}

impl FromStr for Command {
    type Err = Command;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "NICK" => Ok(Command::Nick),
            "USER" => Ok(Command::User),
            "JOIN" => Ok(Command::Join),
            "QUIT" => Ok(Command::Quit),
            "PING" => Ok(Command::Ping),
            "MODE" => Ok(Command::Mode),
            "PASS" => Ok(Command::Pass),
            "PRIVMSG" => Ok(Command::Privmsg),
            _ => Ok(Command::Unknown(s.to_string()))
        }
    }
}

#[derive(Debug)]
pub struct Message {
    pub prefix: Option<String>,
    pub command: Command,
    pub args: Vec<String>,
    pub suffix: Option<String>
}
<commit_msg>irc: protocol: add JOIN<commit_after>use std::str::FromStr;

#[derive(Debug)]
pub enum Command {
    Nick,
    User,
    Join,
    Part,
    Quit,
    Ping,
    Mode,
    Pong,
    Pass,
    Privmsg,
    Numeric(u32),
    Unknown(String)
}

impl Command {
    pub fn as_string(&self) -> String {
        match self {
            &Command::Nick => "NICK".to_string(),
            &Command::Join => "JOIN".to_string(),
            &Command::Part => "PART".to_string(),
            &Command::Pong => "PONG".to_string(),
            &Command::Privmsg => "PRIVMSG".to_string(),
            &Command::User => "USER".to_string(),
            &Command::Quit => "QUIT".to_string(),
            &Command::Ping => "PING".to_string(),
            &Command::Mode => "MODE".to_string(),
            &Command::Pass => "PASS".to_string(),
            &Command::Numeric(n)=> format!("{:0>3}", n),
            &Command::Unknown(ref s) => s.clone()
        }
    }
}

impl Message {
    pub fn to_string(&self) -> String {
        let mut ret = String::new();
        match self.prefix {
            Some(ref pfx) => {
                ret.push(':');
                ret.push_str(pfx.trim());
                ret.push(' ');
            },
            None => ()
        };
        ret.push_str(self.command.as_string().trim());
        for ref arg in self.args.iter() {
            ret.push(' ');
            ret.push_str(arg.trim());
        }

        match self.suffix {
            Some(ref sfx) => {
                ret.push_str(" :");
                ret.push_str(sfx.trim());
            },
            None => ()
        };

        return ret;
    }

    fn split_parts(line: &str) -> (Option<String>, &str, Option<String>) {
        let mut prefix_end = 0;
        let mut args_end = 0;
        if line.chars().nth(0).unwrap() == ':' {
            for c in line[1..].chars() {
                prefix_end += 1;
                if c == ' ' {
                    break
                }
            }
        }

        let mut found_space = false;
        for c in line[prefix_end..].chars() {
            if c == ' ' {
                found_space = true;
            } else if c == ':' && found_space {
                args_end -= 1;
                break
            } else {
                found_space = false;
            }
            args_end += 1;
        }

        let prefix = match prefix_end {
            0 => None,
            _ => Some(line[1..prefix_end].to_string())
        };
        let args = &line[prefix_end..args_end].trim();
        let len = line.len();
        let suffix = if args_end == len {
            None
        } else {
            Some(line[args_end+2..].to_string())
        };

        (prefix, args, suffix)
    }

    pub fn from_str(line: &str) -> Self {
        let parts = Self::split_parts(line.trim());
        let split: Vec<&str> = parts.1.split(" ").collect();
        let mut args = Vec::new();
        for s in split[1..].iter() {
            args.push(s.to_string());
        }
        let parsedCommand: Result<Command, Command> = split[0].parse();
        Message{
            prefix: parts.0,
            command: parsedCommand.ok().unwrap(),
            args: args,
            suffix: parts.2
        }
    }
}

impl From<Command> for Message {
    fn from(c: Command) -> Message {
        Message {
            prefix: None,
            command: c,
            args: vec![],
            suffix: None
        }
    }
}

impl FromStr for Command {
    type Err = Command;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "NICK" => Ok(Command::Nick),
            "USER" => Ok(Command::User),
            "JOIN" => Ok(Command::Join),
            "PART" => Ok(Command::Part),
            "QUIT" => Ok(Command::Quit),
            "PING" => Ok(Command::Ping),
            "MODE" => Ok(Command::Mode),
            "PASS" => Ok(Command::Pass),
            "PRIVMSG" => Ok(Command::Privmsg),
            _ => Ok(Command::Unknown(s.to_string()))
        }
    }
}

#[derive(Debug)]
pub struct Message {
    pub prefix: Option<String>,
    pub command: Command,
    pub args: Vec<String>,
    pub suffix: Option<String>
}
<|endoftext|>


<commit_before>extern crate gl;
extern crate glfw;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};

const VERTEX_SHADER_SOURCE: &'static str = "
    #version 150 core

    in vec2 position;

    void main() {
        gl_Position = vec4(position, 0.0, 1.0);
    }
";

const FRAGMENT_SHADER_SOURCE: &'static str = "
    #version 150 core

    out vec4 out_color;

    void main() {
        out_color = vec4(1.0, 1.0, 1.0, 1.0);
    }
";

unsafe fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
    let shader = gl::CreateShader(shader_type);
    let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
    let source_len = source.len() as GLint;
    gl::ShaderSource(shader, 1, &source_ptr, &source_len);
    gl::CompileShader(shader);

    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status == gl::TRUE as GLint {
        Ok(shader)
    } else {
        let mut log_len = 0;
        gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
        if log_len == 0 { return Err(String::new()) }

        let mut buf = Vec::with_capacity(log_len as usize);
        buf.set_len(log_len as usize - 1); // Subtract 1 to ignore the trailing null.
        gl::GetShaderInfoLog(shader, log_len, std::ptr::null_mut(),
        buf.as_mut_ptr() as *mut GLchar);

        Err(String::from_utf8_lossy(&buf).into_owned())
    }
}

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

    let (mut window, events) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    let vertex_shader;
    let fragment_shader;
    let shader_program;
    let mut vao;
    let mut vbo;

    unsafe {
        // Create a vertex array object.
        vao = 0;
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a vertex buffer object and copy the vertex data to it.
        vbo = 0;
        gl::GenBuffers(1, &mut vbo);

        static VERTICES: [GLfloat; 6] = [
             0.0,  0.5,
             0.5, -0.5,
            -0.5, -0.5,
        ];

        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       (VERTICES.len() * std::mem::size_of::<GLfloat>()) as GLsizeiptr,
                       VERTICES.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Compile the vertex and fragment shaders.
        vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
        fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

        // Link the vertex and fragment shaders into a shader program.
        shader_program = gl::CreateProgram();
        gl::AttachShader(shader_program, vertex_shader);
        gl::AttachShader(shader_program, fragment_shader);
        gl::BindFragDataLocation(shader_program, 0, b"out_color\0".as_ptr() as *const GLchar);
        gl::LinkProgram(shader_program);
        gl::UseProgram(shader_program);

        // Specify the layout of the vertex data.
        let position_attrib = gl::GetAttribLocation(shader_program,
                                                    b"position\0".as_ptr() as *const GLchar);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE, 0,
                                std::ptr::null());
        gl::EnableVertexAttribArray(position_attrib as GLuint);
    }

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        unsafe {
            // Clear the screen to black.
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw a triangle from the 3 vertices.
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
        }

        window.swap_buffers();
    }

    unsafe {
        gl::DeleteProgram(shader_program);
        gl::DeleteShader(fragment_shader);
        gl::DeleteShader(vertex_shader);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<commit_msg>Remove unnecessary GLSL version profile name (core is the default).<commit_after>extern crate gl;
extern crate glfw;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};

const VERTEX_SHADER_SOURCE: &'static str = "
    #version 150

    in vec2 position;

    void main() {
        gl_Position = vec4(position, 0.0, 1.0);
    }
";

const FRAGMENT_SHADER_SOURCE: &'static str = "
    #version 150

    out vec4 out_color;

    void main() {
        out_color = vec4(1.0, 1.0, 1.0, 1.0);
    }
";

unsafe fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
    let shader = gl::CreateShader(shader_type);
    let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
    let source_len = source.len() as GLint;
    gl::ShaderSource(shader, 1, &source_ptr, &source_len);
    gl::CompileShader(shader);

    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status == gl::TRUE as GLint {
        Ok(shader)
    } else {
        let mut log_len = 0;
        gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
        if log_len == 0 { return Err(String::new()) }

        let mut buf = Vec::with_capacity(log_len as usize);
        buf.set_len(log_len as usize - 1); // Subtract 1 to ignore the trailing null.
        gl::GetShaderInfoLog(shader, log_len, std::ptr::null_mut(),
        buf.as_mut_ptr() as *mut GLchar);

        Err(String::from_utf8_lossy(&buf).into_owned())
    }
}

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

    let (mut window, events) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    let vertex_shader;
    let fragment_shader;
    let shader_program;
    let mut vao;
    let mut vbo;

    unsafe {
        // Create a vertex array object.
        vao = 0;
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a vertex buffer object and copy the vertex data to it.
        vbo = 0;
        gl::GenBuffers(1, &mut vbo);

        static VERTICES: [GLfloat; 6] = [
             0.0,  0.5,
             0.5, -0.5,
            -0.5, -0.5,
        ];

        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       (VERTICES.len() * std::mem::size_of::<GLfloat>()) as GLsizeiptr,
                       VERTICES.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Compile the vertex and fragment shaders.
        vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
        fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

        // Link the vertex and fragment shaders into a shader program.
        shader_program = gl::CreateProgram();
        gl::AttachShader(shader_program, vertex_shader);
        gl::AttachShader(shader_program, fragment_shader);
        gl::BindFragDataLocation(shader_program, 0, b"out_color\0".as_ptr() as *const GLchar);
        gl::LinkProgram(shader_program);
        gl::UseProgram(shader_program);

        // Specify the layout of the vertex data.
        let position_attrib = gl::GetAttribLocation(shader_program,
                                                    b"position\0".as_ptr() as *const GLchar);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE, 0,
                                std::ptr::null());
        gl::EnableVertexAttribArray(position_attrib as GLuint);
    }

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        unsafe {
            // Clear the screen to black.
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw a triangle from the 3 vertices.
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
        }

        window.swap_buffers();
    }

    unsafe {
        gl::DeleteProgram(shader_program);
        gl::DeleteShader(fragment_shader);
        gl::DeleteShader(vertex_shader);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Manages the communication between the compiler's main thread and
//! the thread that constructs the dependency graph. The basic idea is
//! to use double buffering to lower the cost of producing a message.
//! In the compiler thread, we accumulate messages in a vector until
//! the vector is full, or until we want to query the graph, and then
//! we send that vector over to the depgraph thread. At the same time,
//! we receive an empty vector from the depgraph thread that we can use
//! to accumulate more messages. This way we only ever have two vectors
//! allocated (and both have a fairly large capacity).

use hir::def_id::DefId;
use rustc_data_structures::veccell::VecCell;
use std::cell::Cell;
use std::sync::mpsc::{self, Sender, Receiver};
use std::thread;

use super::DepGraphQuery;
use super::DepNode;
use super::edges::DepGraphEdges;

pub enum DepMessage {
    Read(DepNode<DefId>),
    Write(DepNode<DefId>),
    PushTask(DepNode<DefId>),
    PopTask(DepNode<DefId>),
    PushIgnore,
    PopIgnore,
    Query,
}

pub struct DepGraphThreadData {
    enabled: bool,

    // Local counter that just tracks how many tasks are pushed onto the
    // stack, so that we still get an error in the case where one is
    // missing. If dep-graph construction is enabled, we'd get the same
    // error when processing tasks later on, but that's annoying because
    // it lacks precision about the source of the error.
    tasks_pushed: Cell<usize>,

    // current buffer, where we accumulate messages
    messages: VecCell<DepMessage>,

    // whence to receive new buffer when full
    swap_in: Receiver<Vec<DepMessage>>,

    // where to send buffer when full
    swap_out: Sender<Vec<DepMessage>>,

    // where to receive query results
    query_in: Receiver<DepGraphQuery<DefId>>,
}

const INITIAL_CAPACITY: usize = 2048;

impl DepGraphThreadData {
    pub fn new(enabled: bool) -> DepGraphThreadData {
        let (tx1, rx1) = mpsc::channel();
        let (tx2, rx2) = mpsc::channel();
        let (txq, rxq) = mpsc::channel();

        if enabled {
            thread::spawn(move || main(rx1, tx2, txq));
        }

        DepGraphThreadData {
            enabled: enabled,
            tasks_pushed: Cell::new(0),
            messages: VecCell::with_capacity(INITIAL_CAPACITY),
            swap_in: rx2,
            swap_out: tx1,
            query_in: rxq,
        }
    }

    #[inline]
    pub fn enabled(&self) -> bool {
        self.enabled
    }

    /// Sends the current batch of messages to the thread. Installs a
    /// new vector of messages.
    fn swap(&self) {
        assert!(self.enabled, "should never swap if not enabled");

        // should be a buffer waiting for us (though of course we may
        // have to wait for depgraph thread to finish processing the
        // old messages)
        let new_messages = self.swap_in.recv().unwrap();
        assert!(new_messages.is_empty());

        // swap in the empty buffer and extract the full one
        let old_messages = self.messages.swap(new_messages);

        // send full buffer to depgraph thread to be processed
        self.swap_out.send(old_messages).unwrap();
    }

    pub fn query(&self) -> DepGraphQuery<DefId> {
        assert!(self.enabled, "cannot query if dep graph construction not enabled");
        self.enqueue(DepMessage::Query);
        self.swap();
        self.query_in.recv().unwrap()
    }

    /// Enqueue a message to be sent when things are next swapped. (If
    /// the buffer is full, this may swap.)
    #[inline]
    pub fn enqueue(&self, message: DepMessage) {
        // Regardless of whether dep graph construction is enabled, we
        // still want to check that we always have a valid task on the
        // stack when a read/write/etc event occurs.
        match message {
            DepMessage::Read(_) | DepMessage::Write(_) =>
                if self.tasks_pushed.get() == 0 {
                    self.invalid_message("read/write but no current task")
                },
            DepMessage::PushTask(_) | DepMessage::PushIgnore =>
                self.tasks_pushed.set(self.tasks_pushed.get() + 1),
            DepMessage::PopTask(_) | DepMessage::PopIgnore =>
                self.tasks_pushed.set(self.tasks_pushed.get() - 1),
            DepMessage::Query =>
                (),
        }

        if self.enabled {
            self.enqueue_enabled(message);
        }
    }

    // Outline this fn since I expect it may want to be inlined
    // separately.
    fn enqueue_enabled(&self, message: DepMessage) {
        let len = self.messages.push(message);
        if len == INITIAL_CAPACITY {
            self.swap();
        }
    }

    // Outline this too.
    fn invalid_message(&self, string: &str) {
        bug!("{}; see src/librustc/dep_graph/README.md for more information", string)
    }
}

/// Definition of the depgraph thread.
pub fn main(swap_in: Receiver<Vec<DepMessage>>,
            swap_out: Sender<Vec<DepMessage>>,
            query_out: Sender<DepGraphQuery<DefId>>) {
    let mut edges = DepGraphEdges::new();

    // the compiler thread always expects a fresh buffer to be
    // waiting, so queue one up
    swap_out.send(Vec::with_capacity(INITIAL_CAPACITY)).unwrap();

    // process the buffers from compiler thread as we receive them
    for mut messages in swap_in {
        for msg in messages.drain(..) {
            match msg {
                DepMessage::Read(node) => edges.read(node),
                DepMessage::Write(node) => edges.write(node),
                DepMessage::PushTask(node) => edges.push_task(node),
                DepMessage::PopTask(node) => edges.pop_task(node),
                DepMessage::PushIgnore => edges.push_ignore(),
                DepMessage::PopIgnore => edges.pop_ignore(),
                DepMessage::Query => query_out.send(edges.query()).unwrap(),
            }
        }
        swap_out.send(messages).unwrap();
    }
}
<commit_msg>Rollup merge of #33313 - birkenfeld:depgraph-panic, r=nikomatsakis<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Manages the communication between the compiler's main thread and
//! the thread that constructs the dependency graph. The basic idea is
//! to use double buffering to lower the cost of producing a message.
//! In the compiler thread, we accumulate messages in a vector until
//! the vector is full, or until we want to query the graph, and then
//! we send that vector over to the depgraph thread. At the same time,
//! we receive an empty vector from the depgraph thread that we can use
//! to accumulate more messages. This way we only ever have two vectors
//! allocated (and both have a fairly large capacity).

use hir::def_id::DefId;
use rustc_data_structures::veccell::VecCell;
use std::cell::Cell;
use std::sync::mpsc::{self, Sender, Receiver};
use std::thread;

use super::DepGraphQuery;
use super::DepNode;
use super::edges::DepGraphEdges;

pub enum DepMessage {
    Read(DepNode<DefId>),
    Write(DepNode<DefId>),
    PushTask(DepNode<DefId>),
    PopTask(DepNode<DefId>),
    PushIgnore,
    PopIgnore,
    Query,
}

pub struct DepGraphThreadData {
    enabled: bool,

    // Local counter that just tracks how many tasks are pushed onto the
    // stack, so that we still get an error in the case where one is
    // missing. If dep-graph construction is enabled, we'd get the same
    // error when processing tasks later on, but that's annoying because
    // it lacks precision about the source of the error.
    tasks_pushed: Cell<usize>,

    // current buffer, where we accumulate messages
    messages: VecCell<DepMessage>,

    // whence to receive new buffer when full
    swap_in: Receiver<Vec<DepMessage>>,

    // where to send buffer when full
    swap_out: Sender<Vec<DepMessage>>,

    // where to receive query results
    query_in: Receiver<DepGraphQuery<DefId>>,
}

const INITIAL_CAPACITY: usize = 2048;

impl DepGraphThreadData {
    pub fn new(enabled: bool) -> DepGraphThreadData {
        let (tx1, rx1) = mpsc::channel();
        let (tx2, rx2) = mpsc::channel();
        let (txq, rxq) = mpsc::channel();

        if enabled {
            thread::spawn(move || main(rx1, tx2, txq));
        }

        DepGraphThreadData {
            enabled: enabled,
            tasks_pushed: Cell::new(0),
            messages: VecCell::with_capacity(INITIAL_CAPACITY),
            swap_in: rx2,
            swap_out: tx1,
            query_in: rxq,
        }
    }

    #[inline]
    pub fn enabled(&self) -> bool {
        self.enabled
    }

    /// Sends the current batch of messages to the thread. Installs a
    /// new vector of messages.
    fn swap(&self) {
        assert!(self.enabled, "should never swap if not enabled");

        // should be a buffer waiting for us (though of course we may
        // have to wait for depgraph thread to finish processing the
        // old messages)
        let new_messages = self.swap_in.recv().unwrap();
        assert!(new_messages.is_empty());

        // swap in the empty buffer and extract the full one
        let old_messages = self.messages.swap(new_messages);

        // send full buffer to depgraph thread to be processed
        self.swap_out.send(old_messages).unwrap();
    }

    pub fn query(&self) -> DepGraphQuery<DefId> {
        assert!(self.enabled, "cannot query if dep graph construction not enabled");
        self.enqueue(DepMessage::Query);
        self.swap();
        self.query_in.recv().unwrap()
    }

    /// Enqueue a message to be sent when things are next swapped. (If
    /// the buffer is full, this may swap.)
    #[inline]
    pub fn enqueue(&self, message: DepMessage) {
        // Regardless of whether dep graph construction is enabled, we
        // still want to check that we always have a valid task on the
        // stack when a read/write/etc event occurs.
        match message {
            DepMessage::Read(_) | DepMessage::Write(_) =>
                if self.tasks_pushed.get() == 0 {
                    self.invalid_message("read/write but no current task")
                },
            DepMessage::PushTask(_) | DepMessage::PushIgnore =>
                self.tasks_pushed.set(self.tasks_pushed.get() + 1),
            DepMessage::PopTask(_) | DepMessage::PopIgnore =>
                self.tasks_pushed.set(self.tasks_pushed.get() - 1),
            DepMessage::Query =>
                (),
        }

        if self.enabled {
            self.enqueue_enabled(message);
        }
    }

    // Outline this fn since I expect it may want to be inlined
    // separately.
    fn enqueue_enabled(&self, message: DepMessage) {
        let len = self.messages.push(message);
        if len == INITIAL_CAPACITY {
            self.swap();
        }
    }

    // Outline this too.
    fn invalid_message(&self, string: &str) {
        bug!("{}; see src/librustc/dep_graph/README.md for more information", string)
    }
}

/// Definition of the depgraph thread.
pub fn main(swap_in: Receiver<Vec<DepMessage>>,
            swap_out: Sender<Vec<DepMessage>>,
            query_out: Sender<DepGraphQuery<DefId>>) {
    let mut edges = DepGraphEdges::new();

    // the compiler thread always expects a fresh buffer to be
    // waiting, so queue one up
    swap_out.send(Vec::with_capacity(INITIAL_CAPACITY)).unwrap();

    // process the buffers from compiler thread as we receive them
    for mut messages in swap_in {
        for msg in messages.drain(..) {
            match msg {
                DepMessage::Read(node) => edges.read(node),
                DepMessage::Write(node) => edges.write(node),
                DepMessage::PushTask(node) => edges.push_task(node),
                DepMessage::PopTask(node) => edges.pop_task(node),
                DepMessage::PushIgnore => edges.push_ignore(),
                DepMessage::PopIgnore => edges.pop_ignore(),
                DepMessage::Query => query_out.send(edges.query()).unwrap(),
            }
        }
        if let Err(_) = swap_out.send(messages) {
            // the receiver must have been dropped already
            break;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Set and unset common attributes on LLVM values.

use std::ffi::{CStr, CString};

use rustc::hir::{self, TransFnAttrFlags};
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::session::config::Sanitizer;
use rustc::ty::TyCtxt;
use rustc::ty::maps::Providers;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::fx::FxHashMap;

use llvm::{self, Attribute, ValueRef};
use llvm::AttributePlace::Function;
use llvm_util;
pub use syntax::attr::{self, InlineAttr};
use context::CodegenCx;

/// Mark LLVM function to use provided inline heuristic.
#[inline]
pub fn inline(val: ValueRef, inline: InlineAttr) {
    use self::InlineAttr::*;
    match inline {
        Hint   => Attribute::InlineHint.apply_llfn(Function, val),
        Always => Attribute::AlwaysInline.apply_llfn(Function, val),
        Never  => Attribute::NoInline.apply_llfn(Function, val),
        None   => {
            Attribute::InlineHint.unapply_llfn(Function, val);
            Attribute::AlwaysInline.unapply_llfn(Function, val);
            Attribute::NoInline.unapply_llfn(Function, val);
        },
    };
}

/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
#[inline]
pub fn emit_uwtable(val: ValueRef, emit: bool) {
    Attribute::UWTable.toggle_llfn(Function, val, emit);
}

/// Tell LLVM whether the function can or cannot unwind.
#[inline]
pub fn unwind(val: ValueRef, can_unwind: bool) {
    Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind);
}

/// Tell LLVM whether it should optimize function for size.
#[inline]
#[allow(dead_code)] // possibly useful function
pub fn set_optimize_for_size(val: ValueRef, optimize: bool) {
    Attribute::OptimizeForSize.toggle_llfn(Function, val, optimize);
}

/// Tell LLVM if this function should be 'naked', i.e. skip the epilogue and prologue.
#[inline]
pub fn naked(val: ValueRef, is_naked: bool) {
    Attribute::Naked.toggle_llfn(Function, val, is_naked);
}

pub fn set_frame_pointer_elimination(cx: &CodegenCx, llfn: ValueRef) {
    // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a
    // parameter.
    if cx.sess().must_not_eliminate_frame_pointers() {
        llvm::AddFunctionAttrStringValue(
            llfn, llvm::AttributePlace::Function,
            cstr("no-frame-pointer-elim\0"), cstr("true\0"));
    }
}

pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) {
    // Only use stack probes if the target specification indicates that we
    // should be using stack probes
    if !cx.sess().target.target.options.stack_probes {
        return
    }

    // Currently stack probes seem somewhat incompatible with the address
    // sanitizer. With asan we're already protected from stack overflow anyway
    // so we don't really need stack probes regardless.
    match cx.sess().opts.debugging_opts.sanitizer {
        Some(Sanitizer::Address) => return,
        _ => {}
    }

    // Flag our internal `__rust_probestack` function as the stack probe symbol.
    // This is defined in the `compiler-builtins` crate for each architecture.
    llvm::AddFunctionAttrStringValue(
        llfn, llvm::AttributePlace::Function,
        cstr("probe-stack\0"), cstr("__rust_probestack\0"));
}

/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
/// attributes.
pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) {
    let trans_fn_attrs = cx.tcx.trans_fn_attrs(id);

    inline(llfn, trans_fn_attrs.inline);

    set_frame_pointer_elimination(cx, llfn);
    set_probestack(cx, llfn);

    if trans_fn_attrs.flags.contains(TransFnAttrFlags::COLD) {
        Attribute::Cold.apply_llfn(Function, llfn);
    }
    if trans_fn_attrs.flags.contains(TransFnAttrFlags::NAKED) {
        naked(llfn, true);
    }
    if trans_fn_attrs.flags.contains(TransFnAttrFlags::ALLOCATOR) {
        Attribute::NoAlias.apply_llfn(
            llvm::AttributePlace::ReturnValue, llfn);
    }
    if trans_fn_attrs.flags.contains(TransFnAttrFlags::UNWIND) {
        unwind(llfn, true);
    }
    if trans_fn_attrs.flags.contains(TransFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) {
        unwind(llfn, false);
    }

    let features =
        trans_fn_attrs.target_features
        .iter()
        .map(|f| {
            let feature = &*f.as_str();
            format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature))
        })
        .collect::<Vec<String>>()
        .join(",");

    if !features.is_empty() {
        let val = CString::new(features).unwrap();
        llvm::AddFunctionAttrStringValue(
            llfn, llvm::AttributePlace::Function,
            cstr("target-features\0"), &val);
    }

    // Note that currently the `wasm-import-module` doesn't do anything, but
    // eventually LLVM 7 should read this and ferry the appropriate import
    // module to the output file.
    if cx.tcx.sess.target.target.arch == "wasm32" {
        if let Some(module) = wasm_import_module(cx.tcx, id) {
            llvm::AddFunctionAttrStringValue(
                llfn,
                llvm::AttributePlace::Function,
                cstr("wasm-import-module\0"),
                &module,
            );
        }
    }
}

fn cstr(s: &'static str) -> &CStr {
    CStr::from_bytes_with_nul(s.as_bytes()).expect("null-terminated string")
}

pub fn provide(providers: &mut Providers) {
    providers.target_features_whitelist = |tcx, cnum| {
        assert_eq!(cnum, LOCAL_CRATE);
        if tcx.sess.opts.actually_rustdoc {
            // rustdoc needs to be able to document functions that use all the features, so
            // whitelist them all
            Lrc::new(llvm_util::all_known_features()
                .map(|c| c.to_string())
                .collect())
        } else {
            Lrc::new(llvm_util::target_feature_whitelist(tcx.sess)
                .iter()
                .map(|c| c.to_string())
                .collect())
        }
    };

    providers.wasm_custom_sections = |tcx, cnum| {
        assert_eq!(cnum, LOCAL_CRATE);
        let mut finder = WasmSectionFinder { tcx, list: Vec::new() };
        tcx.hir.krate().visit_all_item_likes(&mut finder);
        Lrc::new(finder.list)
    };

    provide_extern(providers);
}

struct WasmSectionFinder<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    list: Vec<DefId>,
}

impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for WasmSectionFinder<'a, 'tcx> {
    fn visit_item(&mut self, i: &'tcx hir::Item) {
        match i.node {
            hir::ItemConst(..) => {}
            _ => return,
        }
        if i.attrs.iter().any(|i| i.check_name("wasm_custom_section")) {
            self.list.push(self.tcx.hir.local_def_id(i.id));
        }
    }

    fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {}

    fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {}
}

pub fn provide_extern(providers: &mut Providers) {
    providers.wasm_import_module_map = |tcx, cnum| {
        let mut ret = FxHashMap();
        for lib in tcx.foreign_modules(cnum).iter() {
            let attrs = tcx.get_attrs(lib.def_id);
            let mut module = None;
            for attr in attrs.iter().filter(|a| a.check_name("wasm_import_module")) {
                module = attr.value_str();
            }
            let module = match module {
                Some(s) => s,
                None => continue,
            };
            for id in lib.foreign_items.iter() {
                assert_eq!(id.krate, cnum);
                ret.insert(*id, module.to_string());
            }
        }

        Lrc::new(ret)
    }
}

fn wasm_import_module(tcx: TyCtxt, id: DefId) -> Option<CString> {
    tcx.wasm_import_module_map(id.krate)
        .get(&id)
        .map(|s| CString::new(&s[..]).unwrap())
}
<commit_msg>rustc_trans: disable probestack when using pgo-gen.<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Set and unset common attributes on LLVM values.

use std::ffi::{CStr, CString};

use rustc::hir::{self, TransFnAttrFlags};
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::session::config::Sanitizer;
use rustc::ty::TyCtxt;
use rustc::ty::maps::Providers;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::fx::FxHashMap;

use llvm::{self, Attribute, ValueRef};
use llvm::AttributePlace::Function;
use llvm_util;
pub use syntax::attr::{self, InlineAttr};
use context::CodegenCx;

/// Mark LLVM function to use provided inline heuristic.
#[inline]
pub fn inline(val: ValueRef, inline: InlineAttr) {
    use self::InlineAttr::*;
    match inline {
        Hint   => Attribute::InlineHint.apply_llfn(Function, val),
        Always => Attribute::AlwaysInline.apply_llfn(Function, val),
        Never  => Attribute::NoInline.apply_llfn(Function, val),
        None   => {
            Attribute::InlineHint.unapply_llfn(Function, val);
            Attribute::AlwaysInline.unapply_llfn(Function, val);
            Attribute::NoInline.unapply_llfn(Function, val);
        },
    };
}

/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
#[inline]
pub fn emit_uwtable(val: ValueRef, emit: bool) {
    Attribute::UWTable.toggle_llfn(Function, val, emit);
}

/// Tell LLVM whether the function can or cannot unwind.
#[inline]
pub fn unwind(val: ValueRef, can_unwind: bool) {
    Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind);
}

/// Tell LLVM whether it should optimize function for size.
#[inline]
#[allow(dead_code)] // possibly useful function
pub fn set_optimize_for_size(val: ValueRef, optimize: bool) {
    Attribute::OptimizeForSize.toggle_llfn(Function, val, optimize);
}

/// Tell LLVM if this function should be 'naked', i.e. skip the epilogue and prologue.
#[inline]
pub fn naked(val: ValueRef, is_naked: bool) {
    Attribute::Naked.toggle_llfn(Function, val, is_naked);
}

pub fn set_frame_pointer_elimination(cx: &CodegenCx, llfn: ValueRef) {
    // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a
    // parameter.
    if cx.sess().must_not_eliminate_frame_pointers() {
        llvm::AddFunctionAttrStringValue(
            llfn, llvm::AttributePlace::Function,
            cstr("no-frame-pointer-elim\0"), cstr("true\0"));
    }
}

pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) {
    // Only use stack probes if the target specification indicates that we
    // should be using stack probes
    if !cx.sess().target.target.options.stack_probes {
        return
    }

    // Currently stack probes seem somewhat incompatible with the address
    // sanitizer. With asan we're already protected from stack overflow anyway
    // so we don't really need stack probes regardless.
    match cx.sess().opts.debugging_opts.sanitizer {
        Some(Sanitizer::Address) => return,
        _ => {}
    }

    // probestack doesn't play nice either with pgo-gen.
    if cx.sess().opts.cg.pgo_gen.is_some() {
        return;
    }

    // Flag our internal `__rust_probestack` function as the stack probe symbol.
    // This is defined in the `compiler-builtins` crate for each architecture.
    llvm::AddFunctionAttrStringValue(
        llfn, llvm::AttributePlace::Function,
        cstr("probe-stack\0"), cstr("__rust_probestack\0"));
}

/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
/// attributes.
pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) {
    let trans_fn_attrs = cx.tcx.trans_fn_attrs(id);

    inline(llfn, trans_fn_attrs.inline);

    set_frame_pointer_elimination(cx, llfn);
    set_probestack(cx, llfn);

    if trans_fn_attrs.flags.contains(TransFnAttrFlags::COLD) {
        Attribute::Cold.apply_llfn(Function, llfn);
    }
    if trans_fn_attrs.flags.contains(TransFnAttrFlags::NAKED) {
        naked(llfn, true);
    }
    if trans_fn_attrs.flags.contains(TransFnAttrFlags::ALLOCATOR) {
        Attribute::NoAlias.apply_llfn(
            llvm::AttributePlace::ReturnValue, llfn);
    }
    if trans_fn_attrs.flags.contains(TransFnAttrFlags::UNWIND) {
        unwind(llfn, true);
    }
    if trans_fn_attrs.flags.contains(TransFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) {
        unwind(llfn, false);
    }

    let features =
        trans_fn_attrs.target_features
        .iter()
        .map(|f| {
            let feature = &*f.as_str();
            format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature))
        })
        .collect::<Vec<String>>()
        .join(",");

    if !features.is_empty() {
        let val = CString::new(features).unwrap();
        llvm::AddFunctionAttrStringValue(
            llfn, llvm::AttributePlace::Function,
            cstr("target-features\0"), &val);
    }

    // Note that currently the `wasm-import-module` doesn't do anything, but
    // eventually LLVM 7 should read this and ferry the appropriate import
    // module to the output file.
    if cx.tcx.sess.target.target.arch == "wasm32" {
        if let Some(module) = wasm_import_module(cx.tcx, id) {
            llvm::AddFunctionAttrStringValue(
                llfn,
                llvm::AttributePlace::Function,
                cstr("wasm-import-module\0"),
                &module,
            );
        }
    }
}

fn cstr(s: &'static str) -> &CStr {
    CStr::from_bytes_with_nul(s.as_bytes()).expect("null-terminated string")
}

pub fn provide(providers: &mut Providers) {
    providers.target_features_whitelist = |tcx, cnum| {
        assert_eq!(cnum, LOCAL_CRATE);
        if tcx.sess.opts.actually_rustdoc {
            // rustdoc needs to be able to document functions that use all the features, so
            // whitelist them all
            Lrc::new(llvm_util::all_known_features()
                .map(|c| c.to_string())
                .collect())
        } else {
            Lrc::new(llvm_util::target_feature_whitelist(tcx.sess)
                .iter()
                .map(|c| c.to_string())
                .collect())
        }
    };

    providers.wasm_custom_sections = |tcx, cnum| {
        assert_eq!(cnum, LOCAL_CRATE);
        let mut finder = WasmSectionFinder { tcx, list: Vec::new() };
        tcx.hir.krate().visit_all_item_likes(&mut finder);
        Lrc::new(finder.list)
    };

    provide_extern(providers);
}

struct WasmSectionFinder<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    list: Vec<DefId>,
}

impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for WasmSectionFinder<'a, 'tcx> {
    fn visit_item(&mut self, i: &'tcx hir::Item) {
        match i.node {
            hir::ItemConst(..) => {}
            _ => return,
        }
        if i.attrs.iter().any(|i| i.check_name("wasm_custom_section")) {
            self.list.push(self.tcx.hir.local_def_id(i.id));
        }
    }

    fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {}

    fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {}
}

pub fn provide_extern(providers: &mut Providers) {
    providers.wasm_import_module_map = |tcx, cnum| {
        let mut ret = FxHashMap();
        for lib in tcx.foreign_modules(cnum).iter() {
            let attrs = tcx.get_attrs(lib.def_id);
            let mut module = None;
            for attr in attrs.iter().filter(|a| a.check_name("wasm_import_module")) {
                module = attr.value_str();
            }
            let module = match module {
                Some(s) => s,
                None => continue,
            };
            for id in lib.foreign_items.iter() {
                assert_eq!(id.krate, cnum);
                ret.insert(*id, module.to_string());
            }
        }

        Lrc::new(ret)
    }
}

fn wasm_import_module(tcx: TyCtxt, id: DefId) -> Option<CString> {
    tcx.wasm_import_module_map(id.krate)
        .get(&id)
        .map(|s| CString::new(&s[..]).unwrap())
}
<|endoftext|>


<commit_before>extern crate parity_wasm;

//This module provides some of the simplest exports
//from the Emscripten runtime, such as `STACKTOP` or `abort`.

use std::sync::{Arc, Weak};
use parity_wasm::builder::module;
use parity_wasm::elements::{ExportEntry, Internal, ValueType};
use parity_wasm::interpreter::Error;
use parity_wasm::interpreter::{native_module, UserDefinedElements, UserFunctionDescriptor, UserFunctionExecutor};
use parity_wasm::interpreter::{CallerContext, ModuleInstance, ModuleInstanceInterface};
use parity_wasm::interpreter::RuntimeValue;
use parity_wasm::interpreter::ProgramInstance;
use parity_wasm::interpreter::{VariableInstance, VariableType};

/// Memory address, at which stack begins.
const DEFAULT_STACK_TOP: u32 = 256 * 1024;
/// Memory, allocated for stack.
const DEFAULT_TOTAL_STACK: u32 = 5 * 1024 * 1024;
/// Total memory, allocated by default.
const DEFAULT_TOTAL_MEMORY: u32 = 16 * 1024 * 1024;
/// Whether memory can be enlarged, or not.
const DEFAULT_ALLOW_MEMORY_GROWTH: bool = true;
/// Default tableBase variable value.
const DEFAULT_TABLE_BASE: u32 = 0;
/// Default tableBase variable value.
const DEFAULT_MEMORY_BASE: u32 = 0;

/// Default table size.
const DEFAULT_TABLE_SIZE: u32 = 64;

/// Index of default memory.
const INDEX_MEMORY: u32 = 0;

/// Index of default table.
const INDEX_TABLE: u32 = 0;

const LINEAR_MEMORY_PAGE_SIZE: u32 = 64 * 1024;

/// Emscripten environment parameters.
pub struct EmscriptenParams {
	/// Stack size in bytes.
	pub total_stack: u32,
	/// Total memory size in bytes.
	pub total_memory: u32,
	/// Allow memory growth.
	pub allow_memory_growth: bool,
	/// Table size.
	pub table_size: u32,
	/// Static reserve, if any
	pub static_size: Option<u32>,
}

struct EmscriptenFunctionExecutor {
	total_mem_global: Arc<VariableInstance>,
}

impl<'a> UserFunctionExecutor for EmscriptenFunctionExecutor {
	fn execute(
		&mut self,
		name: &str,
		context: CallerContext,
	) -> Result<Option<RuntimeValue>, Error> {
		match name {
			"_abort" | "abort" => {
				Err(Error::Trap("abort".into()).into())
			}
			"assert" => {
				let condition = context.value_stack.pop_as::<i32>()?;
				if condition == 0 {
					Err(Error::Trap("assertion failed".into()))
				} else {
					Ok(None)
				}
			}
			"enlargeMemory" => {
				// TODO: support memory enlarge
				Ok(Some(RuntimeValue::I32(0)))
			}
			"getTotalMemory" => {
				let total_memory = self.total_mem_global.get();
				Ok(Some(total_memory))
			}
			_ => Err(Error::Trap("not implemented".into()).into()),
		}
	}
}

pub fn env_module(params: EmscriptenParams) -> Result<Arc<ModuleInstanceInterface>, Error> {
	debug_assert!(params.total_stack < params.total_memory);
	debug_assert!((params.total_stack % LINEAR_MEMORY_PAGE_SIZE) == 0);
	debug_assert!((params.total_memory % LINEAR_MEMORY_PAGE_SIZE) == 0);

	let stack_top = params.static_size.unwrap_or(DEFAULT_STACK_TOP);

	// Build module with defined memory and table,
	// instantiate it and wrap into an Arc.
	let instance = {
		let builder = module()
			// memory regions
			.memory()
				.with_min(params.total_memory / LINEAR_MEMORY_PAGE_SIZE)
				.with_max(params.max_memory().map(|m| m / LINEAR_MEMORY_PAGE_SIZE))
				.build()
				.with_export(ExportEntry::new("memory".into(), Internal::Memory(INDEX_MEMORY)))
			// tables
			.table()
				.with_min(params.table_size)
				.build()
				.with_export(ExportEntry::new("table".into(), Internal::Table(INDEX_TABLE)));
		let mut instance = ModuleInstance::new(Weak::default(), "env".into(), builder.build())?;
		instance.instantiate(None)?;
		Arc::new(instance)
	};
	let total_mem_global = Arc::new(
		VariableInstance::new(
			false,
			VariableType::I32,
			RuntimeValue::I32(params.total_memory as i32),
		).unwrap(),
	);

	let function_executor = EmscriptenFunctionExecutor {
		total_mem_global: Arc::clone(&total_mem_global),
	};

	const SIGNATURES: &'static [UserFunctionDescriptor] = &[
		UserFunctionDescriptor::Static("_abort", &[], None),
		UserFunctionDescriptor::Static("abort", &[], None),
		UserFunctionDescriptor::Static("assert", &[ValueType::I32], None),
		UserFunctionDescriptor::Static("enlargeMemory", &[], Some(ValueType::I32)),
		UserFunctionDescriptor::Static("getTotalMemory", &[], Some(ValueType::I32)),
	];

	let elements = UserDefinedElements {
		executor: Some(function_executor),
		globals: vec![
			(
				"STACK_BASE".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(stack_top as i32),
					).unwrap(),
				),
			),
			(
				"STACKTOP".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(stack_top as i32),
					).unwrap(),
				),
			),
			(
				"STACK_MAX".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32((stack_top + params.total_stack) as i32),
					).unwrap(),
				),
			),
			(
				"DYNAMIC_BASE".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32((stack_top + params.total_stack) as i32),
					).unwrap(),
				),
			),
			(
				"DYNAMICTOP_PTR".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32((stack_top + params.total_stack) as i32),
					).unwrap(),
				),
			),
			(
				"EXITSTATUS".into(),
				Arc::new(
					VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(0)).unwrap(),
				),
			),
			(
				"tableBase".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(DEFAULT_TABLE_BASE as i32),
					).unwrap(),
				),
			),
			(
				"memoryBase".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(DEFAULT_MEMORY_BASE as i32),
					).unwrap(),
				),
			),
			("TOTAL_MEMORY".into(), total_mem_global),
		].into_iter()
			.collect(),
		functions: ::std::borrow::Cow::from(SIGNATURES),
	};

	Ok(native_module(instance, elements)?)
}

impl Default for EmscriptenParams {
	fn default() -> Self {
		EmscriptenParams {
			total_stack: DEFAULT_TOTAL_STACK,
			total_memory: DEFAULT_TOTAL_MEMORY,
			allow_memory_growth: DEFAULT_ALLOW_MEMORY_GROWTH,
			table_size: DEFAULT_TABLE_SIZE,
			static_size: None,
		}
	}
}

impl EmscriptenParams {
	fn max_memory(&self) -> Option<u32> {
		if self.allow_memory_growth { None } else { Some(self.total_memory) }
	}
}

pub fn program_with_emscripten_env(params: EmscriptenParams) -> Result<ProgramInstance, Error> {
	let program = ProgramInstance::new();
	program.insert_loaded_module("env", env_module(params)?)?;
	Ok(program)
}

#[cfg(test)]
mod tests {
	use super::program_with_emscripten_env;
	use parity_wasm::builder::module;
	use parity_wasm::elements::{ImportEntry, External, GlobalType, ValueType};

	#[test]
	fn import_env_mutable_global() {
		let program = program_with_emscripten_env(Default::default()).unwrap();

		let module = module()
			.with_import(ImportEntry::new("env".into(), "STACKTOP".into(), External::Global(GlobalType::new(ValueType::I32, false))))
			.build();

		program.add_module("main", module, None).unwrap();
	}
}
<commit_msg>Review fixes.<commit_after>//! This crate provides some of the simplest exports
//! from the Emscripten runtime, such as `STACKTOP` or `abort`.

extern crate parity_wasm;

use std::sync::{Arc, Weak};
use parity_wasm::builder::module;
use parity_wasm::elements::{ExportEntry, Internal, ValueType};
use parity_wasm::interpreter::Error;
use parity_wasm::interpreter::{native_module, UserDefinedElements, UserFunctionDescriptor, UserFunctionExecutor};
use parity_wasm::interpreter::{CallerContext, ModuleInstance, ModuleInstanceInterface};
use parity_wasm::interpreter::RuntimeValue;
use parity_wasm::interpreter::ProgramInstance;
use parity_wasm::interpreter::{VariableInstance, VariableType};

/// Memory address, at which stack begins.
const DEFAULT_STACK_TOP: u32 = 256 * 1024;
/// Memory, allocated for stack.
const DEFAULT_TOTAL_STACK: u32 = 5 * 1024 * 1024;
/// Total memory, allocated by default.
const DEFAULT_TOTAL_MEMORY: u32 = 16 * 1024 * 1024;
/// Whether memory can be enlarged, or not.
const DEFAULT_ALLOW_MEMORY_GROWTH: bool = true;
/// Default tableBase variable value.
const DEFAULT_TABLE_BASE: u32 = 0;
/// Default tableBase variable value.
const DEFAULT_MEMORY_BASE: u32 = 0;

/// Default table size.
const DEFAULT_TABLE_SIZE: u32 = 64;

/// Index of default memory.
const INDEX_MEMORY: u32 = 0;

/// Index of default table.
const INDEX_TABLE: u32 = 0;

const LINEAR_MEMORY_PAGE_SIZE: u32 = 64 * 1024;

/// Emscripten environment parameters.
pub struct EmscriptenParams {
	/// Stack size in bytes.
	pub total_stack: u32,
	/// Total memory size in bytes.
	pub total_memory: u32,
	/// Allow memory growth.
	pub allow_memory_growth: bool,
	/// Table size.
	pub table_size: u32,
	/// Static reserve, if any
	pub static_size: Option<u32>,
}

struct EmscriptenFunctionExecutor {
	total_mem_global: Arc<VariableInstance>,
}

impl<'a> UserFunctionExecutor for EmscriptenFunctionExecutor {
	fn execute(
		&mut self,
		name: &str,
		context: CallerContext,
	) -> Result<Option<RuntimeValue>, Error> {
		match name {
			"_abort" | "abort" => {
				Err(Error::Trap("abort".into()).into())
			},
			"assert" => {
				let condition = context.value_stack.pop_as::<i32>()?;
				if condition == 0 {
					Err(Error::Trap("assertion failed".into()))
				} else {
					Ok(None)
				}
			},
			"enlargeMemory" => {
				// TODO: support memory enlarge
				Ok(Some(RuntimeValue::I32(0)))
			},
			"getTotalMemory" => {
				let total_memory = self.total_mem_global.get();
				Ok(Some(total_memory))
			},
			_ => Err(Error::Trap("not implemented".into()).into()),
		}
	}
}

pub fn env_module(params: EmscriptenParams) -> Result<Arc<ModuleInstanceInterface>, Error> {
	debug_assert!(params.total_stack < params.total_memory);
	debug_assert!((params.total_stack % LINEAR_MEMORY_PAGE_SIZE) == 0);
	debug_assert!((params.total_memory % LINEAR_MEMORY_PAGE_SIZE) == 0);

	let stack_top = params.static_size.unwrap_or(DEFAULT_STACK_TOP);

	// Build module with defined memory and table,
	// instantiate it and wrap into an Arc.
	let instance = {
		let builder = module()
			// memory regions
			.memory()
				.with_min(params.total_memory / LINEAR_MEMORY_PAGE_SIZE)
				.with_max(params.max_memory().map(|m| m / LINEAR_MEMORY_PAGE_SIZE))
				.build()
				.with_export(ExportEntry::new("memory".into(), Internal::Memory(INDEX_MEMORY)))
			// tables
			.table()
				.with_min(params.table_size)
				.build()
				.with_export(ExportEntry::new("table".into(), Internal::Table(INDEX_TABLE)));
		let mut instance = ModuleInstance::new(Weak::default(), "env".into(), builder.build())?;
		instance.instantiate(None)?;
		Arc::new(instance)
	};
	let total_mem_global = Arc::new(
		VariableInstance::new(
			false,
			VariableType::I32,
			RuntimeValue::I32(params.total_memory as i32),
		).unwrap(),
	);

	let function_executor = EmscriptenFunctionExecutor {
		total_mem_global: Arc::clone(&total_mem_global),
	};

	const SIGNATURES: &'static [UserFunctionDescriptor] = &[
		UserFunctionDescriptor::Static("_abort", &[], None),
		UserFunctionDescriptor::Static("abort", &[], None),
		UserFunctionDescriptor::Static("assert", &[ValueType::I32], None),
		UserFunctionDescriptor::Static("enlargeMemory", &[], Some(ValueType::I32)),
		UserFunctionDescriptor::Static("getTotalMemory", &[], Some(ValueType::I32)),
	];

	let elements = UserDefinedElements {
		executor: Some(function_executor),
		globals: vec![
			(
				"STACK_BASE".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(stack_top as i32),
					).unwrap(),
				),
			),
			(
				"STACKTOP".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(stack_top as i32),
					).unwrap(),
				),
			),
			(
				"STACK_MAX".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32((stack_top + params.total_stack) as i32),
					).unwrap(),
				),
			),
			(
				"DYNAMIC_BASE".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32((stack_top + params.total_stack) as i32),
					).unwrap(),
				),
			),
			(
				"DYNAMICTOP_PTR".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32((stack_top + params.total_stack) as i32),
					).unwrap(),
				),
			),
			(
				"EXITSTATUS".into(),
				Arc::new(
					VariableInstance::new(false, VariableType::I32, RuntimeValue::I32(0)).unwrap(),
				),
			),
			(
				"tableBase".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(DEFAULT_TABLE_BASE as i32),
					).unwrap(),
				),
			),
			(
				"memoryBase".into(),
				Arc::new(
					VariableInstance::new(
						false,
						VariableType::I32,
						RuntimeValue::I32(DEFAULT_MEMORY_BASE as i32),
					).unwrap(),
				),
			),
			("TOTAL_MEMORY".into(), total_mem_global),
		].into_iter()
			.collect(),
		functions: ::std::borrow::Cow::from(SIGNATURES),
	};

	Ok(native_module(instance, elements)?)
}

impl Default for EmscriptenParams {
	fn default() -> Self {
		EmscriptenParams {
			total_stack: DEFAULT_TOTAL_STACK,
			total_memory: DEFAULT_TOTAL_MEMORY,
			allow_memory_growth: DEFAULT_ALLOW_MEMORY_GROWTH,
			table_size: DEFAULT_TABLE_SIZE,
			static_size: None,
		}
	}
}

impl EmscriptenParams {
	fn max_memory(&self) -> Option<u32> {
		if self.allow_memory_growth { None } else { Some(self.total_memory) }
	}
}

pub fn program_with_emscripten_env(params: EmscriptenParams) -> Result<ProgramInstance, Error> {
	let program = ProgramInstance::new();
	program.insert_loaded_module("env", env_module(params)?)?;
	Ok(program)
}

#[cfg(test)]
mod tests {
	use super::program_with_emscripten_env;
	use parity_wasm::builder::module;
	use parity_wasm::elements::{ImportEntry, External, GlobalType, ValueType};

	#[test]
	fn import_env_mutable_global() {
		let program = program_with_emscripten_env(Default::default()).unwrap();

		let module = module()
			.with_import(ImportEntry::new("env".into(), "STACKTOP".into(), External::Global(GlobalType::new(ValueType::I32, false))))
			.build();

		program.add_module("main", module, None).unwrap();
	}
}
<|endoftext|>