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

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("SVG", inherited=False, gecko_name="SVGReset") %>

// TODO: Which of these should be animatable properties?
${helpers.single_keyword("dominant-baseline",
                 """auto use-script no-change reset-size ideographic alphabetic hanging
                    mathematical central middle text-after-edge text-before-edge""",
                 products="gecko",
                 animatable=False)}

${helpers.single_keyword("vector-effect", "none non-scaling-stroke",
                         products="gecko", animatable=False)}

// Section 13 - Gradients and Patterns

${helpers.predefined_type(
    "stop-color", "CSSColor",
    "CSSParserColor::RGBA(RGBA { red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0 })",
    products="gecko",
    animatable=False)}

${helpers.predefined_type("stop-opacity", "Opacity", "1.0",
                          products="gecko",
                          animatable=False)}

// Section 15 - Filter Effects

${helpers.predefined_type(
    "flood-color", "CSSColor",
    "CSSParserColor::RGBA(RGBA { red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0 })",
    products="gecko",
    animatable=False)}

${helpers.predefined_type("flood-opacity", "Opacity",
                          "1.0", products="gecko", animatable=False)}

${helpers.predefined_type(
    "lighting-color", "CSSColor",
    "CSSParserColor::RGBA(RGBA { red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0 })",
    products="gecko",
    animatable=False)}

// CSS Masking Module Level 1
// https://www.w3.org/TR/css-masking-1/
${helpers.single_keyword("mask-type", "luminance alpha",
                         products="gecko", animatable=False)}

<%helpers:longhand name="clip-path" animatable="False" products="gecko">
    use std::fmt;
    use style_traits::ToCss;
    use values::NoViewportPercentage;
    use values::specified::basic_shape::{ShapeSource, GeometryBox};

    pub mod computed_value {
        use app_units::Au;
        use values::computed::basic_shape::{ShapeSource, GeometryBox};

        pub type T = ShapeSource<GeometryBox>;
    }

    pub type SpecifiedValue = ShapeSource<GeometryBox>;

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        Default::default()
    }

    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        ShapeSource::parse(context, input)
    }

    impl NoViewportPercentage for SpecifiedValue {}
</%helpers:longhand>

${helpers.single_keyword("mask-mode",
                         "alpha luminance match-source",
                         vector=True,
                         products="gecko",
                         animatable=False)}

// TODO implement all of repeat-style for background and mask
// https://drafts.csswg.org/css-backgrounds-3/#repeat-style
${helpers.single_keyword("mask-repeat",
                         "repeat repeat-x repeat-y space round no-repeat",
                         vector=True,
                         products="gecko",
                         animatable=False)}

<%helpers:vector_longhand name="mask-position" products="gecko" animatable="True">
    use std::fmt;
    use style_traits::ToCss;
    use values::HasViewportPercentage;
    use values::specified::position::Position;

    pub mod computed_value {
        use values::computed::position::Position;
        use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
        use properties::longhands::mask_position::computed_value::T as MaskPosition;

        pub type T = Position;

        impl RepeatableListInterpolate for MaskPosition {}

        impl Interpolate for MaskPosition {
            fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
                Ok(MaskPosition(try!(self.0.interpolate(&other.0, progress))))
            }
        }
    }

    pub type SpecifiedValue = Position;

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        use values::computed::position::Position;
        Position {
            horizontal: computed::LengthOrPercentage::Percentage(0.0),
            vertical: computed::LengthOrPercentage::Percentage(0.0),
        }
    }
    #[inline]
    pub fn get_initial_specified_value() -> SpecifiedValue {
        use values::specified::Percentage;
        use values::specified::position::{HorizontalPosition, VerticalPosition};
        Position {
            horizontal: HorizontalPosition {
                keyword: None,
                position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))),
            },
            vertical: VerticalPosition {
                keyword: None,
                position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))),
            },
        }
    }

    pub fn parse(context: &ParserContext, input: &mut Parser)
                 -> Result<SpecifiedValue, ()> {
        Position::parse(context, input)
    }
</%helpers:vector_longhand>

// missing: margin-box fill-box stroke-box view-box no-clip
// (gecko doesn't implement these)
${helpers.single_keyword("mask-clip",
                         "content-box padding-box border-box",
                         vector=True,
                         products="gecko",
                         animatable=False)}

// missing: margin-box fill-box stroke-box view-box
// (gecko doesn't implement these)
${helpers.single_keyword("mask-origin",
                         "content-box padding-box border-box",
                         vector=True,
                         products="gecko",
                         animatable=False)}

<%helpers:longhand name="mask-size" products="gecko" animatable="True">
    use properties::longhands::background_size;
    pub use ::properties::longhands::background_size::SpecifiedValue;
    pub use ::properties::longhands::background_size::single_value as single_value;
    pub use ::properties::longhands::background_size::computed_value as computed_value;

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        background_size::get_initial_value()
    }

    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
        background_size::parse(context, input)
    }
</%helpers:longhand>

${helpers.single_keyword("mask-composite",
                         "add subtract intersect exclude",
                         vector=True,
                         products="gecko",
                         animatable=False)}

<%helpers:vector_longhand name="mask-image" products="gecko" animatable="False"
                          has_uncacheable_values="${product == 'gecko'}">
    use std::fmt;
    use style_traits::ToCss;
    use std::sync::Arc;
    use values::specified::Image;
    use values::specified::url::SpecifiedUrl;
    use values::NoViewportPercentage;

    pub mod computed_value {
        use std::fmt;
        use style_traits::ToCss;
        use values::computed;
        use values::specified::url::SpecifiedUrl;
        #[derive(Debug, Clone, PartialEq)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum T {
            Image(computed::Image),
            Url(SpecifiedUrl),
            None
        }

        impl ToCss for T {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                match *self {
                    T::None => dest.write_str("none"),
                    T::Image(ref image) => image.to_css(dest),
                    T::Url(ref url) => url.to_css(dest),
                }
            }
        }
    }

    impl NoViewportPercentage for SpecifiedValue {}

    #[derive(Debug, Clone, PartialEq)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    pub enum SpecifiedValue {
        Image(Image),
        Url(SpecifiedUrl),
        None
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            match *self {
                SpecifiedValue::Image(ref image) => image.to_css(dest),
                SpecifiedValue::Url(ref url) => url.to_css(dest),
                SpecifiedValue::None => dest.write_str("none"),
            }
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T::None
    }
    #[inline]
    pub fn get_initial_specified_value() -> SpecifiedValue {
        SpecifiedValue::None
    }
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            Ok(SpecifiedValue::None)
        } else {
            let image = try!(Image::parse(context, input));
            match image {
                Image::Url(url_value) => {
                    let has_valid_url = match url_value.url() {
                        Some(url) => url.fragment().is_some(),
                        None => false,
                    };

                    if has_valid_url {
                        Ok(SpecifiedValue::Url(url_value))
                    } else {
                        Ok(SpecifiedValue::Image(Image::Url(url_value)))
                    }
                }
                image => Ok(SpecifiedValue::Image(image))
            }
        }
    }
    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, context: &Context) -> computed_value::T {
            match *self {
                SpecifiedValue::None => computed_value::T::None,
                SpecifiedValue::Image(ref image) =>
                    computed_value::T::Image(image.to_computed_value(context)),
                SpecifiedValue::Url(ref url) =>
                    computed_value::T::Url(url.clone()),
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> Self {
            match *computed {
                computed_value::T::None => SpecifiedValue::None,
                computed_value::T::Image(ref image) =>
                    SpecifiedValue::Image(ToComputedValue::from_computed_value(image)),
                computed_value::T::Url(ref url) =>
                    SpecifiedValue::Url(url.clone()),
            }
        }
    }
</%helpers:vector_longhand>
<commit_msg>Add spec links for svg properties<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("SVG", inherited=False, gecko_name="SVGReset") %>

// TODO: Which of these should be animatable properties?
${helpers.single_keyword("dominant-baseline",
                 """auto use-script no-change reset-size ideographic alphabetic hanging
                    mathematical central middle text-after-edge text-before-edge""",
                 products="gecko",
                 animatable=False,
                 spec="https://www.w3.org/TR/SVG11/text.html#DominantBaselineProperty")}

${helpers.single_keyword("vector-effect", "none non-scaling-stroke",
                         products="gecko", animatable=False,
                         spec="https://www.w3.org/TR/SVGTiny12/painting.html#VectorEffectProperty")}

// Section 13 - Gradients and Patterns

${helpers.predefined_type(
    "stop-color", "CSSColor",
    "CSSParserColor::RGBA(RGBA { red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0 })",
    products="gecko",
    animatable=False,
    spec="https://www.w3.org/TR/SVGTiny12/painting.html#StopColorProperty")}

${helpers.predefined_type("stop-opacity", "Opacity", "1.0",
                          products="gecko",
                          animatable=False,
                          spec="https://www.w3.org/TR/SVGTiny12/painting.html#propdef-stop-opacity")}

// Section 15 - Filter Effects

${helpers.predefined_type(
    "flood-color", "CSSColor",
    "CSSParserColor::RGBA(RGBA { red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0 })",
    products="gecko",
    animatable=False,
    spec="https://www.w3.org/TR/SVG/filters.html#FloodColorProperty")}

${helpers.predefined_type("flood-opacity", "Opacity",
                          "1.0", products="gecko", animatable=False,
                          spec="https://www.w3.org/TR/SVG/filters.html#FloodOpacityProperty")}

${helpers.predefined_type(
    "lighting-color", "CSSColor",
    "CSSParserColor::RGBA(RGBA { red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0 })",
    products="gecko",
    animatable=False,
    spec="https://www.w3.org/TR/SVG/filters.html#LightingColorProperty")}

// CSS Masking Module Level 1
// https://drafts.fxtf.org/css-masking
${helpers.single_keyword("mask-type", "luminance alpha",
                         products="gecko", animatable=False,
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type")}

<%helpers:longhand name="clip-path" animatable="False" products="gecko"
                   spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path">
    use std::fmt;
    use style_traits::ToCss;
    use values::NoViewportPercentage;
    use values::specified::basic_shape::{ShapeSource, GeometryBox};

    pub mod computed_value {
        use app_units::Au;
        use values::computed::basic_shape::{ShapeSource, GeometryBox};

        pub type T = ShapeSource<GeometryBox>;
    }

    pub type SpecifiedValue = ShapeSource<GeometryBox>;

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        Default::default()
    }

    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        ShapeSource::parse(context, input)
    }

    impl NoViewportPercentage for SpecifiedValue {}
</%helpers:longhand>

${helpers.single_keyword("mask-mode",
                         "alpha luminance match-source",
                         vector=True,
                         products="gecko",
                         animatable=False,
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-mode")}

// TODO implement all of repeat-style for background and mask
// https://drafts.csswg.org/css-backgrounds-3/#repeat-style
${helpers.single_keyword("mask-repeat",
                         "repeat repeat-x repeat-y space round no-repeat",
                         vector=True,
                         products="gecko",
                         animatable=False,
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-repeat")}

<%helpers:vector_longhand name="mask-position" products="gecko" animatable="True"
                          spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position">
    use std::fmt;
    use style_traits::ToCss;
    use values::HasViewportPercentage;
    use values::specified::position::Position;

    pub mod computed_value {
        use values::computed::position::Position;
        use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
        use properties::longhands::mask_position::computed_value::T as MaskPosition;

        pub type T = Position;

        impl RepeatableListInterpolate for MaskPosition {}

        impl Interpolate for MaskPosition {
            fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
                Ok(MaskPosition(try!(self.0.interpolate(&other.0, progress))))
            }
        }
    }

    pub type SpecifiedValue = Position;

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        use values::computed::position::Position;
        Position {
            horizontal: computed::LengthOrPercentage::Percentage(0.0),
            vertical: computed::LengthOrPercentage::Percentage(0.0),
        }
    }
    #[inline]
    pub fn get_initial_specified_value() -> SpecifiedValue {
        use values::specified::Percentage;
        use values::specified::position::{HorizontalPosition, VerticalPosition};
        Position {
            horizontal: HorizontalPosition {
                keyword: None,
                position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))),
            },
            vertical: VerticalPosition {
                keyword: None,
                position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))),
            },
        }
    }

    pub fn parse(context: &ParserContext, input: &mut Parser)
                 -> Result<SpecifiedValue, ()> {
        Position::parse(context, input)
    }
</%helpers:vector_longhand>

// missing: margin-box fill-box stroke-box view-box no-clip
// (gecko doesn't implement these)
${helpers.single_keyword("mask-clip",
                         "content-box padding-box border-box",
                         vector=True,
                         products="gecko",
                         animatable=False,
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-clip")}

// missing: margin-box fill-box stroke-box view-box
// (gecko doesn't implement these)
${helpers.single_keyword("mask-origin",
                         "content-box padding-box border-box",
                         vector=True,
                         products="gecko",
                         animatable=False,
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-origin")}

<%helpers:longhand name="mask-size" products="gecko" animatable="True"
                   spec="https://drafts.fxtf.org/css-masking/#propdef-mask-size">
    use properties::longhands::background_size;
    pub use ::properties::longhands::background_size::SpecifiedValue;
    pub use ::properties::longhands::background_size::single_value as single_value;
    pub use ::properties::longhands::background_size::computed_value as computed_value;

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        background_size::get_initial_value()
    }

    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
        background_size::parse(context, input)
    }
</%helpers:longhand>

${helpers.single_keyword("mask-composite",
                         "add subtract intersect exclude",
                         vector=True,
                         products="gecko",
                         animatable=False,
                         spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")}

<%helpers:vector_longhand name="mask-image" products="gecko" animatable="False"
                          has_uncacheable_values="${product == 'gecko'}",
                          spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image">
    use std::fmt;
    use style_traits::ToCss;
    use std::sync::Arc;
    use values::specified::Image;
    use values::specified::url::SpecifiedUrl;
    use values::NoViewportPercentage;

    pub mod computed_value {
        use std::fmt;
        use style_traits::ToCss;
        use values::computed;
        use values::specified::url::SpecifiedUrl;
        #[derive(Debug, Clone, PartialEq)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum T {
            Image(computed::Image),
            Url(SpecifiedUrl),
            None
        }

        impl ToCss for T {
            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
                match *self {
                    T::None => dest.write_str("none"),
                    T::Image(ref image) => image.to_css(dest),
                    T::Url(ref url) => url.to_css(dest),
                }
            }
        }
    }

    impl NoViewportPercentage for SpecifiedValue {}

    #[derive(Debug, Clone, PartialEq)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    pub enum SpecifiedValue {
        Image(Image),
        Url(SpecifiedUrl),
        None
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            match *self {
                SpecifiedValue::Image(ref image) => image.to_css(dest),
                SpecifiedValue::Url(ref url) => url.to_css(dest),
                SpecifiedValue::None => dest.write_str("none"),
            }
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T::None
    }
    #[inline]
    pub fn get_initial_specified_value() -> SpecifiedValue {
        SpecifiedValue::None
    }
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            Ok(SpecifiedValue::None)
        } else {
            let image = try!(Image::parse(context, input));
            match image {
                Image::Url(url_value) => {
                    let has_valid_url = match url_value.url() {
                        Some(url) => url.fragment().is_some(),
                        None => false,
                    };

                    if has_valid_url {
                        Ok(SpecifiedValue::Url(url_value))
                    } else {
                        Ok(SpecifiedValue::Image(Image::Url(url_value)))
                    }
                }
                image => Ok(SpecifiedValue::Image(image))
            }
        }
    }
    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, context: &Context) -> computed_value::T {
            match *self {
                SpecifiedValue::None => computed_value::T::None,
                SpecifiedValue::Image(ref image) =>
                    computed_value::T::Image(image.to_computed_value(context)),
                SpecifiedValue::Url(ref url) =>
                    computed_value::T::Url(url.clone()),
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> Self {
            match *computed {
                computed_value::T::None => SpecifiedValue::None,
                computed_value::T::Image(ref image) =>
                    SpecifiedValue::Image(ToComputedValue::from_computed_value(image)),
                computed_value::T::Url(ref url) =>
                    SpecifiedValue::Url(url.clone()),
            }
        }
    }
</%helpers:vector_longhand>
<|endoftext|>


<commit_before>//! Defines `RadecoProject`, `RadecoModule` and `RadecoFunction`.
//! Temporarily defines `Loader` and `Source`.
//!
//!
//!
//! Example Usage
//! ====
//!
//! Default example:
//! ```rust
//! let options = LoadOptions::default();
//! let mut loader = R2ProjectLoader::new();
//! let mut rp = loader.load("/bin/ls", load_options);
//! for mut ref rmod in rp.iter_mod_mut() {
//!     loader.load_functions(rmod)?;
//! }
//!
//! for mut ref rmod in rp.iter_mod_mut() {
//!     for mut ref rfn in rmod.iter_fn_mut() {
//!         // Construct SSA, Do some analysis.
//!     }
//! }
//! ```
//!
//! Example with custom function loader/detection:
//! ```
//! ...
//! let mut fident = FunctionIdentifier::new();
//! let mut ref rmod is rp.itrer_mod_mut() {
//!     fident.identify_functions(rmod);
//! }
//! ```

use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap};
use std::collections::{btree_map, hash_map};
use std::path::Path;

use petgraph::graph::NodeIndex;

use r2pipe::r2::R2;
use r2api::structs::{LOpInfo, LRegInfo};
use r2api::api_trait::R2Api;

use middle::ssa::ssastorage::SSAStorage;
use frontend::bindings::{Binding, RBindings, RadecoBindings};
use frontend::source::Source;

pub trait ProjectLoader {
    fn load<T: AsRef<str>>(T, Option<ProjectOptions>) -> Result<RadecoProject, String>;
}

#[derive(Debug, Default)]
pub struct ProjectOptions {
    load_libs: bool,
    load_path: Cow<'static, str>,
}

#[derive(Debug)]
/// Top level overall project
pub struct RadecoProject {
    /// Map of loaded modules
    modules: HashMap<String, RadecoModule>,
    /// Register/Arch information for loaded project
    /// TODO: Discuss and replace with arch
    reginfo: LRegInfo,
}

#[derive(Debug)]
/// Container to store information about a single loaded binary or library.
pub struct RadecoModule {
    /// Flag to check if functions are loaded/indentified
    are_functions_loaded: bool,
    // TODO: Placeholder. Fix this with real graph.
    /// Call graph for current module
    call_graph: Option<String>,
    /// Map of functions loaded
    functions: BTreeMap<u64, RadecoFunction>,
    // TODO: This needs to be something better than just a String.
    /// List of imports for the current module
    imports: Vec<String>,
    /// Library name
    name: Cow<'static, str>,
    /// Path on disk to the loaded library
    path: Cow<'static, str>,
    // TODO:
    // sections: ,
    // symbols: ,
    // loader: ,
    // imports: ,
    // exports: ,
}

#[derive(Debug)]
pub struct CallRefs {
    /// Offset of the caller function
    caller_fn_offset: u64,
    /// Offset of callee function
    callee_fn_offset: u64,
    /// Offset of the call instruction
    call_site_offset: u64,
}

#[derive(Debug)]
pub enum FunctionType {
    /// Function defined in the current binary
    Function,
    /// Import from another module. Set to u16::max_value() to represent `Unknown`
    /// Fixed up when the corresponding library that defines this function is loaded
    Import(u16),
}

pub const UNKNOWN_MODULE: u16 = 0xFFFF;

#[derive(Debug)]
/// Container to store information about identified function.
/// Used as a basic unit in intra-functional analysis.
pub struct RadecoFunction {
    /// Identified variable bindings for `RadecoFunction`
    bindings: RadecoBindings<Binding<NodeIndex>>,
    /// Current module being analyzed, i.e., the index of the module that returned this
    /// RadecoFunction instance. Note that this is not necessarily
    /// the module where the function is defined, in case of an import.
    current_module: u16,
    /// Represents the type of function
    ftype: FunctionType,
    /// Raw instruction information for the current function
    pub instructions: Vec<LOpInfo>,
    /// Is current function known to be recursive
    is_recursive: bool,
    /// Human readable name for the function. Taken either from
    /// the symbol table or assigned based on offset.
    pub name: Cow<'static, str>,
    /// Start address of the function
    pub offset: u64,
    /// Calls to the function
    refs: Vec<CallRefs>,
    /// Size of the function in bytes
    size: u64,
    /// Constructed SSA for the function
    ssa: SSAStorage,
    /// Calls from the current function to other functions
    xrefs: Vec<CallRefs>,
}

#[derive(Debug)]
/// Default project loader that uses r2 and r2pipe
/// Implements the `ProjectLoader` trait
pub struct R2ProjectLoader { }

#[derive(Debug)]
/// Load a RadecoProject from formatted JSON files
pub struct JSONProjectLoader { }

impl RadecoProject {
    pub fn new() -> RadecoProject {
        RadecoProject {
            modules: HashMap::new(),
            reginfo: LRegInfo::default(),
        }
    }

    pub fn new_module(&mut self,
                      module_path: String) -> Result<&mut RadecoModule, &'static str> {
        let module_name = Path::new(&module_path).file_stem().unwrap();
        let module_name_str = module_name.to_str().unwrap().to_owned();
        if self.modules.contains_key(&module_name_str) {
            Err("Module with same name already loaded")
        } else {
            let rmod = RadecoModule::new(module_path.clone());
            self.modules.insert(module_name_str.clone(), rmod);
            Ok(self.modules.get_mut(&module_name_str).unwrap())
        }
    }

    pub fn modules(&self) -> hash_map::Values<String, RadecoModule> {
        self.modules.values()
    }

    pub fn modules_mut(&mut self) -> hash_map::ValuesMut<String, RadecoModule> {
        self.modules.values_mut()
    }

    pub fn reginfo(&self) -> &LRegInfo {
        &self.reginfo
    }

    pub fn set_reginfo(&mut self, reginfo: LRegInfo) {
        self.reginfo = reginfo;
    }
}

impl RadecoModule {
    pub fn new(path: String) -> RadecoModule {
        RadecoModule {
            are_functions_loaded: false,
            call_graph: None,
            functions: BTreeMap::new(),
            imports: Vec::new(),
            name: Cow::from(path.clone()),
            // FIXME
            path: Cow::from(path),
        }
    }

    pub fn new_function_at(&mut self, offset: u64) -> Result<&mut RadecoFunction, &'static str> {
        if self.functions.contains_key(&offset) {
            return Err("Function already defined at current `offset`")
        } else {
            self.functions.insert(offset, RadecoFunction::new(offset, 0));
            Ok(self.functions.get_mut(&offset).unwrap())
        }
    }

    pub fn function_at(&self, offset: &u64) -> Option<&RadecoFunction> {
        self.functions.get(offset)
    }

    pub fn functions(&self) -> btree_map::Values<u64, RadecoFunction> {
        self.functions.values()
    }

    pub fn functions_mut(&mut self) -> btree_map::ValuesMut<u64, RadecoFunction> {
        self.functions.values_mut()
    }
}

impl RadecoFunction {
    pub fn new(offset: u64, size: u64) -> RadecoFunction {
        let name = format!("fun{:x}", offset);
        RadecoFunction {
            bindings: RadecoBindings::new(),
            current_module: UNKNOWN_MODULE,
            ftype: FunctionType::Function,
            instructions: Vec::new(),
            is_recursive: false,
            name: Cow::from(name),
            offset: offset,
            refs: Vec::new(),
            size: size,
            ssa: SSAStorage::new(),
            xrefs: Vec::new(),
        }
    }

    pub fn ssa(&self) -> &SSAStorage {
        &self.ssa
    }

    pub fn ssa_mut(&mut self) -> &mut SSAStorage {
        &mut self.ssa
    }
}

impl ProjectLoader for R2ProjectLoader {
    fn load<T: AsRef<str>>(bin: T,
                           options: Option<ProjectOptions>)
        -> Result<RadecoProject, String>
    {
        // TODO: Parse/use option
        let options = options.unwrap_or(ProjectOptions::default());
        let bpath = String::from(bin.as_ref());
        let mut r2 = R2::new(Some(bin.as_ref()))?;
        r2.init();
        let mut rp = RadecoProject::new();
        rp.set_reginfo(r2.reg_info().expect("Unable to load `LRegInfo`"));
        {
            // TODO: Setup the project with more information,
            // such as: arch, platform etc.
            let mut main_mod = rp.new_module(bpath)?;
            // TODO: Load more information such as sections, symbol table, global defines,
            // constant strings etc.
            main_mod.are_functions_loaded = true;
            for function in r2.functions() {
                let name = function.name.as_ref().unwrap();
                let offset = function.offset.expect("Invalid offset");
                let ref mut rfn = main_mod.new_function_at(offset)?;
                rfn.name = Cow::from(name.to_owned());
                rfn.ftype = if name.contains("sym.imp") {
                    FunctionType::Import(UNKNOWN_MODULE)
                } else {
                    FunctionType::Function
                };
                let insts = r2.instructions_at(offset);
                rfn.instructions = insts;
            }
        }
        Ok(rp)
    }
}
<commit_msg>Implements more containers framework<commit_after>//! Defines `RadecoProject`, `RadecoModule` and `RadecoFunction`.
//! Temporarily defines `Loader` and `Source`.
//!
//!
//!
//! Example Usage
//! ====
//!
//! Default example:
//! ```rust
//! let options = LoadOptions::default();
//! let mut loader = R2ProjectLoader::new();
//! let mut rp = loader.load("/bin/ls", load_options);
//! for mut ref rmod in rp.iter_mod_mut() {
//!     loader.load_functions(rmod)?;
//! }
//!
//! for mut ref rmod in rp.iter_mod_mut() {
//!     for mut ref rfn in rmod.iter_fn_mut() {
//!         // Construct SSA, Do some analysis.
//!     }
//! }
//! ```
//!
//! Example with custom function loader/detection:
//! ```
//! ...
//! let mut fident = FunctionIdentifier::new();
//! let mut ref rmod is rp.itrer_mod_mut() {
//!     fident.identify_functions(rmod);
//! }
//! ```

use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap};
use std::collections::{btree_map, hash_map};
use std::path::Path;

use petgraph::graph::NodeIndex;

use r2pipe::r2::R2;
use r2api::structs::{LOpInfo, LRegInfo};
use r2api::api_trait::R2Api;

use middle::ssa::ssastorage::SSAStorage;
use frontend::bindings::{Binding, RBindings, RadecoBindings};
use frontend::source::Source;

//pub trait ProjectLoader {
    //fn load<T: AsRef<str>>(T, Option<ProjectOptions>) -> Result<RadecoProject, String>;
//}

#[derive(Debug, Default)]
pub struct ProjectOptions {
    load_libs: bool,
    load_path: Cow<'static, str>,
}

#[derive(Debug)]
/// Top level overall project
pub struct RadecoProject {
    /// Map of loaded modules
    modules: HashMap<String, RadecoModule>,
    /// Register/Arch information for loaded project
    /// TODO: Discuss and replace with arch
    reginfo: LRegInfo,
}

#[derive(Debug)]
/// Container to store information about a single loaded binary or library.
pub struct RadecoModule {
    /// Flag to check if functions are loaded/indentified
    are_functions_loaded: bool,
    // TODO: Placeholder. Fix this with real graph.
    /// Call graph for current module
    call_graph: Option<String>,
    /// Map of functions loaded
    functions: BTreeMap<u64, RadecoFunction>,
    // TODO: This needs to be something better than just a String.
    /// List of imports for the current module
    imports: Vec<String>,
    /// Library name
    name: Cow<'static, str>,
    /// Path on disk to the loaded library
    path: Cow<'static, str>,
    // TODO:
    // sections: ,
    // symbols: ,
    // loader: ,
    // imports: ,
    // exports: ,
}

#[derive(Debug)]
pub struct CallRefs {
    /// Offset of the caller function
    caller_fn_offset: u64,
    /// Offset of callee function
    callee_fn_offset: u64,
    /// Offset of the call instruction
    call_site_offset: u64,
}

#[derive(Debug, Clone)]
pub enum FunctionType {
    /// Function defined in the current binary
    Function,
    /// Import from another module. Set to u16::max_value() to represent `Unknown`
    /// Fixed up when the corresponding library that defines this function is loaded
    Import(u16),
}

pub const UNKNOWN_MODULE: u16 = 0xFFFF;

#[derive(Debug, Clone)]
/// Container to store information about identified function.
/// Used as a basic unit in intra-functional analysis.
pub struct RadecoFunction {
    /// Identified variable bindings for `RadecoFunction`
    bindings: RadecoBindings<Binding<NodeIndex>>,
    /// Current module being analyzed, i.e., the index of the module that returned this
    /// RadecoFunction instance. Note that this is not necessarily
    /// the module where the function is defined, in case of an import.
    current_module: u16,
    /// Represents the type of function
    ftype: FunctionType,
    /// Raw instruction information for the current function
    pub instructions: Vec<LOpInfo>,
    /// Is current function known to be recursive
    is_recursive: bool,
    /// Human readable name for the function. Taken either from
    /// the symbol table or assigned based on offset.
    pub name: Cow<'static, str>,
    /// Start address of the function
    pub offset: u64,
    // Calls to the function
    //refs: Vec<CallRefs>,
    /// Size of the function in bytes
    size: u64,
    /// Constructed SSA for the function
    ssa: SSAStorage,
    // Calls from the current function to other functions
    //xrefs: Vec<CallRefs>,
}

//#[derive(Debug)]
// Default project loader that uses r2 and r2pipe
// Implements the `ProjectLoader` trait
//pub struct R2ProjectLoader { }

//#[derive(Debug)]
// Load a RadecoProject from formatted JSON files
//pub struct JSONProjectLoader { }

pub struct ProjectLoader<'a> {
    load_libs: bool,
    mloader: Option<ModuleLoader<'a>>,
}

pub struct ModuleLoader<'a> {
    source: Box<Source>,
    floader: Option<FunctionLoader<'a>>,
    filter: Option<fn (x: RadecoFunction) -> bool>,
}

pub trait PredicatedLoader {
    fn predicate(&self, x: &FLResult) -> bool;
    fn strategy(&self, last: &FLResult, rmod: &RadecoModule) -> FLResult;
}

impl<T> PredicatedLoader for T
where T: Fn (&FLResult, &RadecoModule) -> FLResult {
    fn predicate(&self, x: &FLResult) -> bool { true }
    fn strategy(&self, last: &FLResult, rmod: &RadecoModule) -> FLResult {
        self(last, rmod)
    }
}

#[derive(Debug, Default)]
pub struct FLResult {
    functions: Vec<RadecoFunction>,
    new: u32,
}

#[derive(Default)]
pub struct FunctionLoader<'a> {
    strategies: Vec<&'a PredicatedLoader>,
}

impl<'a> FunctionLoader<'a> {
    pub fn strategy<'b: 'a>(mut self, strat: &'b PredicatedLoader) -> FunctionLoader<'a> {
        self.strategies.push(strat);
        self
    }

    // TODO: Add default strats
    pub fn load(&mut self, rmod: &RadecoModule) -> FLResult {
        self.strategies.iter().fold(FLResult::default(), |mut acc, f| {
            if f.predicate(&acc) {
                let fl = f.strategy(&acc, rmod);
                acc.new += fl.new;
                acc.functions.extend(fl.functions.iter().cloned());
            }
            acc
        })
    }
}

impl RadecoProject {
    pub fn new() -> RadecoProject {
        RadecoProject {
            modules: HashMap::new(),
            reginfo: LRegInfo::default(),
        }
    }

    pub fn new_module(&mut self,
                      module_path: String) -> Result<&mut RadecoModule, &'static str> {
        let module_name = Path::new(&module_path).file_stem().unwrap();
        let module_name_str = module_name.to_str().unwrap().to_owned();
        if self.modules.contains_key(&module_name_str) {
            Err("Module with same name already loaded")
        } else {
            let rmod = RadecoModule::new(module_path.clone());
            self.modules.insert(module_name_str.clone(), rmod);
            Ok(self.modules.get_mut(&module_name_str).unwrap())
        }
    }

    pub fn modules(&self) -> hash_map::Values<String, RadecoModule> {
        self.modules.values()
    }

    pub fn modules_mut(&mut self) -> hash_map::ValuesMut<String, RadecoModule> {
        self.modules.values_mut()
    }

    pub fn reginfo(&self) -> &LRegInfo {
        &self.reginfo
    }

    pub fn set_reginfo(&mut self, reginfo: LRegInfo) {
        self.reginfo = reginfo;
    }
}

impl RadecoModule {
    pub fn new(path: String) -> RadecoModule {
        RadecoModule {
            are_functions_loaded: false,
            call_graph: None,
            functions: BTreeMap::new(),
            imports: Vec::new(),
            name: Cow::from(path.clone()),
            // FIXME
            path: Cow::from(path),
        }
    }

    pub fn new_function_at(&mut self, offset: u64) -> Result<&mut RadecoFunction, &'static str> {
        if self.functions.contains_key(&offset) {
            return Err("Function already defined at current `offset`")
        } else {
            self.functions.insert(offset, RadecoFunction::new(offset, 0));
            Ok(self.functions.get_mut(&offset).unwrap())
        }
    }

    pub fn function_at(&self, offset: &u64) -> Option<&RadecoFunction> {
        self.functions.get(offset)
    }

    pub fn functions(&self) -> btree_map::Values<u64, RadecoFunction> {
        self.functions.values()
    }

    pub fn functions_mut(&mut self) -> btree_map::ValuesMut<u64, RadecoFunction> {
        self.functions.values_mut()
    }
}

impl RadecoFunction {
    pub fn new(offset: u64, size: u64) -> RadecoFunction {
        let name = format!("fun{:x}", offset);
        RadecoFunction {
            bindings: RadecoBindings::new(),
            current_module: UNKNOWN_MODULE,
            ftype: FunctionType::Function,
            instructions: Vec::new(),
            is_recursive: false,
            name: Cow::from(name),
            offset: offset,
            //refs: Vec::new(),
            size: size,
            ssa: SSAStorage::new(),
            //xrefs: Vec::new(),
        }
    }

    pub fn ssa(&self) -> &SSAStorage {
        &self.ssa
    }

    pub fn ssa_mut(&mut self) -> &mut SSAStorage {
        &mut self.ssa
    }
}

//impl ProjectLoader for R2ProjectLoader {
    //fn load<T: AsRef<str>>(bin: T,
                           //options: Option<ProjectOptions>)
        //-> Result<RadecoProject, String>
    //{
        //// TODO: Parse/use option
        //let options = options.unwrap_or(ProjectOptions::default());
        //let bpath = String::from(bin.as_ref());
        //let mut r2 = R2::new(Some(bin.as_ref()))?;
        //r2.init();
        //let mut rp = RadecoProject::new();
        //rp.set_reginfo(r2.reg_info().expect("Unable to load `LRegInfo`"));
        //{
            //// TODO: Setup the project with more information,
            //// such as: arch, platform etc.
            //let mut main_mod = rp.new_module(bpath)?;
            //// TODO: Load more information such as sections, symbol table, global defines,
            //// constant strings etc.
            //main_mod.are_functions_loaded = true;
            //for function in r2.functions() {
                //let name = function.name.as_ref().unwrap();
                //let offset = function.offset.expect("Invalid offset");
                //let ref mut rfn = main_mod.new_function_at(offset)?;
                //rfn.name = Cow::from(name.to_owned());
                //rfn.ftype = if name.contains("sym.imp") {
                    //FunctionType::Import(UNKNOWN_MODULE)
                //} else {
                    //FunctionType::Function
                //};
                //let insts = r2.instructions_at(offset);
                //rfn.instructions = insts;
            //}
        //}
        //Ok(rp)
    //}
//}

// Function Loader.
//
// Function loader takes in a module, as a part of the module loader process
// and chunks it down to individual functions.
// The actual implementation of this may vary depending on the needs,
// from simply reading off from the symbol table to performing analysis
// to figure out function boundaries.
// In any case, at the end of this process, the module should be broken down
// into several functions.
//
// More complex loaders, example: using symbol table when available and performing
// analysis otherwise, may be composed and built from simpler ones.
//pub trait FunctionLoader: Sized {
    //fn function_loader(rmod: &RadecoModule) -> Self;
    //fn load() -> Self;
//}

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

    #[test]
    fn test_fn_loader() {
        let ld = |x: &FLResult, y: &RadecoModule| -> FLResult {
            unimplemented!()
        };

        let mut fl = FunctionLoader::default();
        fl.strategy(&ld);
    }
}
<|endoftext|>


<commit_before>// # Basic Example
//
// This example covers the basic functionalities of
// tantivy.
//
// We will :
// - define our schema
// - create an index in a directory
// - index a few documents into our index
// - search for the best document matching a basic query
// - retrieve the best document's original content.

// ---
// Importing tantivy...
use tantivy::collector::TopDocs;
use tantivy::query::QueryParser;
use tantivy::schema::*;
use tantivy::{doc, Index, ReloadPolicy};
use tempfile::TempDir;

fn main() -> tantivy::Result<()> {
    // Let's create a temporary directory for the
    // sake of this example
    let index_path = TempDir::new()?;

    // # Defining the schema
    //
    // The Tantivy index requires a very strict schema.
    // The schema declares which fields are in the index,
    // and for each field, its type and "the way it should
    // be indexed".

    // First we need to define a schema ...
    let mut schema_builder = Schema::builder();

    // Our first field is title.
    // We want full-text search for it, and we also want
    // to be able to retrieve the document after the search.
    //
    // `TEXT | STORED` is some syntactic sugar to describe
    // that.
    //
    // `TEXT` means the field should be tokenized and indexed,
    // along with its term frequency and term positions.
    //
    // `STORED` means that the field will also be saved
    // in a compressed, row-oriented key-value store.
    // This store is useful for reconstructing the
    // documents that were selected during the search phase.
    schema_builder.add_text_field("title", TEXT | STORED);

    // Our second field is body.
    // We want full-text search for it, but we do not
    // need to be able to be able to retrieve it
    // for our application.
    //
    // We can make our index lighter by omitting the `STORED` flag.
    schema_builder.add_text_field("body", TEXT);

    let schema = schema_builder.build();

    // # Indexing documents
    //
    // Let's create a brand new index.
    //
    // This will actually just save a meta.json
    // with our schema in the directory.
    let index = Index::create_in_dir(&index_path, schema.clone())?;

    // To insert a document we will need an index writer.
    // There must be only one writer at a time.
    // This single `IndexWriter` is already
    // multithreaded.
    //
    // Here we give tantivy a budget of `50MB`.
    // Using a bigger heap for the indexer may increase
    // throughput, but 50 MB is already plenty.
    let mut index_writer = index.writer(50_000_000)?;

    // Let's index our documents!
    // We first need a handle on the title and the body field.

    // ### Adding documents
    //
    // We can create a document manually, by setting the fields
    // one by one in a Document object.
    let title = schema.get_field("title").unwrap();
    let body = schema.get_field("body").unwrap();

    let mut old_man_doc = Document::default();
    old_man_doc.add_text(title, "The Old Man and the Sea");
    old_man_doc.add_text(
        body,
        "He was an old man who fished alone in a skiff in the Gulf Stream and \
         he had gone eighty-four days now without taking a fish.",
    );

    // ... and add it to the `IndexWriter`.
    index_writer.add_document(old_man_doc);

    // For convenience, tantivy also comes with a macro to
    // reduce the boilerplate above.
    index_writer.add_document(doc!(
    title => "Of Mice and Men",
    body => "A few miles south of Soledad, the Salinas River drops in close to the hillside \
            bank and runs deep and green. The water is warm too, for it has slipped twinkling \
            over the yellow sands in the sunlight before reaching the narrow pool. On one \
            side of the river the golden foothill slopes curve up to the strong and rocky \
            Gabilan Mountains, but on the valley side the water is lined with trees—willows \
            fresh and green with every spring, carrying in their lower leaf junctures the \
            debris of the winter’s flooding; and sycamores with mottled, white, recumbent \
            limbs and branches that arch over the pool"
    ));

    index_writer.add_document(doc!(
    title => "Of Mice and Men",
    body => "A few miles south of Soledad, the Salinas River drops in close to the hillside \
            bank and runs deep and green. The water is warm too, for it has slipped twinkling \
            over the yellow sands in the sunlight before reaching the narrow pool. On one \
            side of the river the golden foothill slopes curve up to the strong and rocky \
            Gabilan Mountains, but on the valley side the water is lined with trees—willows \
            fresh and green with every spring, carrying in their lower leaf junctures the \
            debris of the winter’s flooding; and sycamores with mottled, white, recumbent \
            limbs and branches that arch over the pool"
    ));

    // Multivalued field just need to be repeated.
    index_writer.add_document(doc!(
    title => "Frankenstein",
    title => "The Modern Prometheus",
    body => "You will rejoice to hear that no disaster has accompanied the commencement of an \
             enterprise which you have regarded with such evil forebodings.  I arrived here \
             yesterday, and my first task is to assure my dear sister of my welfare and \
             increasing confidence in the success of my undertaking."
    ));

    // This is an example, so we will only index 3 documents
    // here. You can check out tantivy's tutorial to index
    // the English wikipedia. Tantivy's indexing is rather fast.
    // Indexing 5 million articles of the English wikipedia takes
    // around 3 minutes on my computer!

    // ### Committing
    //
    // At this point our documents are not searchable.
    //
    //
    // We need to call `.commit()` explicitly to force the
    // `index_writer` to finish processing the documents in the queue,
    // flush the current index to the disk, and advertise
    // the existence of new documents.
    //
    // This call is blocking.
    index_writer.commit()?;

    // If `.commit()` returns correctly, then all of the
    // documents that have been added are guaranteed to be
    // persistently indexed.
    //
    // In the scenario of a crash or a power failure,
    // tantivy behaves as if it has rolled back to its last
    // commit.

    // # Searching
    //
    // ### Searcher
    //
    // A reader is required first in order to search an index.
    // It acts as a `Searcher` pool that reloads itself,
    // depending on a `ReloadPolicy`.
    //
    // For a search server you will typically create one reader for the entire lifetime of your
    // program, and acquire a new searcher for every single request.
    //
    // In the code below, we rely on the 'ON_COMMIT' policy: the reader
    // will reload the index automatically after each commit.
    let reader = index
        .reader_builder()
        .reload_policy(ReloadPolicy::OnCommit)
        .try_into()?;

    // We now need to acquire a searcher.
    //
    // A searcher points to a snapshotted, immutable version of the index.
    //
    // Some search experience might require more than
    // one query. Using the same searcher ensures that all of these queries will run on the
    // same version of the index.
    //
    // Acquiring a `searcher` is very cheap.
    //
    // You should acquire a searcher every time you start processing a request and
    // and release it right after your query is finished.
    let searcher = reader.searcher();

    // ### Query

    // The query parser can interpret human queries.
    // Here, if the user does not specify which
    // field they want to search, tantivy will search
    // in both title and body.
    let query_parser = QueryParser::for_index(&index, vec![title, body]);

    // `QueryParser` may fail if the query is not in the right
    // format. For user facing applications, this can be a problem.
    // A ticket has been opened regarding this problem.
    let query = query_parser.parse_query("sea whale")?;

    // A query defines a set of documents, as
    // well as the way they should be scored.
    //
    // A query created by the query parser is scored according
    // to a metric called Tf-Idf, and will consider
    // any document matching at least one of our terms.

    // ### Collectors
    //
    // We are not interested in all of the documents but
    // only in the top 10. Keeping track of our top 10 best documents
    // is the role of the `TopDocs` collector.

    // We can now perform our query.
    let top_docs = searcher.search(&query, &TopDocs::with_limit(10))?;

    // The actual documents still need to be
    // retrieved from Tantivy's store.
    //
    // Since the body field was not configured as stored,
    // the document returned will only contain
    // a title.
    for (_score, doc_address) in top_docs {
        let retrieved_doc = searcher.doc(doc_address)?;
        println!("{}", schema.to_json(&retrieved_doc));
    }

    Ok(())
}
<commit_msg>Update basic_search.rs (#865)<commit_after>// # Basic Example
//
// This example covers the basic functionalities of
// tantivy.
//
// We will :
// - define our schema
// - create an index in a directory
// - index a few documents into our index
// - search for the best document matching a basic query
// - retrieve the best document's original content.

// ---
// Importing tantivy...
use tantivy::collector::TopDocs;
use tantivy::query::QueryParser;
use tantivy::schema::*;
use tantivy::{doc, Index, ReloadPolicy};
use tempfile::TempDir;

fn main() -> tantivy::Result<()> {
    // Let's create a temporary directory for the
    // sake of this example
    let index_path = TempDir::new()?;

    // # Defining the schema
    //
    // The Tantivy index requires a very strict schema.
    // The schema declares which fields are in the index,
    // and for each field, its type and "the way it should
    // be indexed".

    // First we need to define a schema ...
    let mut schema_builder = Schema::builder();

    // Our first field is title.
    // We want full-text search for it, and we also want
    // to be able to retrieve the document after the search.
    //
    // `TEXT | STORED` is some syntactic sugar to describe
    // that.
    //
    // `TEXT` means the field should be tokenized and indexed,
    // along with its term frequency and term positions.
    //
    // `STORED` means that the field will also be saved
    // in a compressed, row-oriented key-value store.
    // This store is useful for reconstructing the
    // documents that were selected during the search phase.
    schema_builder.add_text_field("title", TEXT | STORED);

    // Our second field is body.
    // We want full-text search for it, but we do not
    // need to be able to be able to retrieve it
    // for our application.
    //
    // We can make our index lighter by omitting the `STORED` flag.
    schema_builder.add_text_field("body", TEXT);

    let schema = schema_builder.build();

    // # Indexing documents
    //
    // Let's create a brand new index.
    //
    // This will actually just save a meta.json
    // with our schema in the directory.
    let index = Index::create_in_dir(&index_path, schema.clone())?;

    // To insert a document we will need an index writer.
    // There must be only one writer at a time.
    // This single `IndexWriter` is already
    // multithreaded.
    //
    // Here we give tantivy a budget of `50MB`.
    // Using a bigger heap for the indexer may increase
    // throughput, but 50 MB is already plenty.
    let mut index_writer = index.writer(50_000_000)?;

    // Let's index our documents!
    // We first need a handle on the title and the body field.

    // ### Adding documents
    //
    // We can create a document manually, by setting the fields
    // one by one in a Document object.
    let title = schema.get_field("title").unwrap();
    let body = schema.get_field("body").unwrap();

    let mut old_man_doc = Document::default();
    old_man_doc.add_text(title, "The Old Man and the Sea");
    old_man_doc.add_text(
        body,
        "He was an old man who fished alone in a skiff in the Gulf Stream and \
         he had gone eighty-four days now without taking a fish.",
    );

    // ... and add it to the `IndexWriter`.
    index_writer.add_document(old_man_doc);

    // For convenience, tantivy also comes with a macro to
    // reduce the boilerplate above.
    index_writer.add_document(doc!(
    title => "Of Mice and Men",
    body => "A few miles south of Soledad, the Salinas River drops in close to the hillside \
            bank and runs deep and green. The water is warm too, for it has slipped twinkling \
            over the yellow sands in the sunlight before reaching the narrow pool. On one \
            side of the river the golden foothill slopes curve up to the strong and rocky \
            Gabilan Mountains, but on the valley side the water is lined with trees—willows \
            fresh and green with every spring, carrying in their lower leaf junctures the \
            debris of the winter’s flooding; and sycamores with mottled, white, recumbent \
            limbs and branches that arch over the pool"
    ));

    // Multivalued field just need to be repeated.
    index_writer.add_document(doc!(
    title => "Frankenstein",
    title => "The Modern Prometheus",
    body => "You will rejoice to hear that no disaster has accompanied the commencement of an \
             enterprise which you have regarded with such evil forebodings.  I arrived here \
             yesterday, and my first task is to assure my dear sister of my welfare and \
             increasing confidence in the success of my undertaking."
    ));

    // This is an example, so we will only index 3 documents
    // here. You can check out tantivy's tutorial to index
    // the English wikipedia. Tantivy's indexing is rather fast.
    // Indexing 5 million articles of the English wikipedia takes
    // around 3 minutes on my computer!

    // ### Committing
    //
    // At this point our documents are not searchable.
    //
    //
    // We need to call `.commit()` explicitly to force the
    // `index_writer` to finish processing the documents in the queue,
    // flush the current index to the disk, and advertise
    // the existence of new documents.
    //
    // This call is blocking.
    index_writer.commit()?;

    // If `.commit()` returns correctly, then all of the
    // documents that have been added are guaranteed to be
    // persistently indexed.
    //
    // In the scenario of a crash or a power failure,
    // tantivy behaves as if it has rolled back to its last
    // commit.

    // # Searching
    //
    // ### Searcher
    //
    // A reader is required first in order to search an index.
    // It acts as a `Searcher` pool that reloads itself,
    // depending on a `ReloadPolicy`.
    //
    // For a search server you will typically create one reader for the entire lifetime of your
    // program, and acquire a new searcher for every single request.
    //
    // In the code below, we rely on the 'ON_COMMIT' policy: the reader
    // will reload the index automatically after each commit.
    let reader = index
        .reader_builder()
        .reload_policy(ReloadPolicy::OnCommit)
        .try_into()?;

    // We now need to acquire a searcher.
    //
    // A searcher points to a snapshotted, immutable version of the index.
    //
    // Some search experience might require more than
    // one query. Using the same searcher ensures that all of these queries will run on the
    // same version of the index.
    //
    // Acquiring a `searcher` is very cheap.
    //
    // You should acquire a searcher every time you start processing a request and
    // and release it right after your query is finished.
    let searcher = reader.searcher();

    // ### Query

    // The query parser can interpret human queries.
    // Here, if the user does not specify which
    // field they want to search, tantivy will search
    // in both title and body.
    let query_parser = QueryParser::for_index(&index, vec![title, body]);

    // `QueryParser` may fail if the query is not in the right
    // format. For user facing applications, this can be a problem.
    // A ticket has been opened regarding this problem.
    let query = query_parser.parse_query("sea whale")?;

    // A query defines a set of documents, as
    // well as the way they should be scored.
    //
    // A query created by the query parser is scored according
    // to a metric called Tf-Idf, and will consider
    // any document matching at least one of our terms.

    // ### Collectors
    //
    // We are not interested in all of the documents but
    // only in the top 10. Keeping track of our top 10 best documents
    // is the role of the `TopDocs` collector.

    // We can now perform our query.
    let top_docs = searcher.search(&query, &TopDocs::with_limit(10))?;

    // The actual documents still need to be
    // retrieved from Tantivy's store.
    //
    // Since the body field was not configured as stored,
    // the document returned will only contain
    // a title.
    for (_score, doc_address) in top_docs {
        let retrieved_doc = searcher.doc(doc_address)?;
        println!("{}", schema.to_json(&retrieved_doc));
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::error::Error;

use handlebars::JsonRender;

use handlebars::{handlebars_helper, Handlebars};
use time::format_description::parse;
use time::OffsetDateTime;

// define a helper using helper
// a date format helper accept an `OffsetDateTime` as parameter
handlebars_helper!(date: |dt: OffsetDateTime| dt.format(&parse("[year]-[month]-[day]").unwrap()).unwrap());

// a helper returns number of provided parameters
handlebars_helper!(nargs: |*args| args.len());

// a helper joins all values, using both hash and parameters
handlebars_helper!(join: |{sep:str=","}, *args|
                   args.iter().map(|a| a.render()).collect::<Vec<String>>().join(sep)
);

// a helper provides format
handlebars_helper!(date2: |dt: OffsetDateTime, {fmt:str = "[year]-[month]-[day]"}|
    dt.format(&parse(fmt).unwrap()).unwrap()
);

fn main() -> Result<(), Box<dyn Error>> {
    // create the handlebars registry
    let mut handlebars = Handlebars::new();

    handlebars.register_helper("date", Box::new(date));
    handlebars.register_helper("date2", Box::new(date2));
    handlebars.register_helper("nargs", Box::new(nargs));
    handlebars.register_helper("join", Box::new(join));

    let data = OffsetDateTime::now_utc();

    println!("{}", handlebars.render_template("{{date this}}", &data)?);
    println!("{}", handlebars.render_template("{{date2 this}}", &data)?);
    println!(
        "{}",
        handlebars.render_template("{{date2 this fmt=\"[day]/[month]/[year]\"}}", &data)?
    );

    println!("{}", handlebars.render_template("{{nargs 1 2 3 4}}", &())?);

    println!(
        "{}",
        handlebars.render_template("{{join 1 2 3 4 sep=\"|\" }}", &())?
    );

    Ok(())
}
<commit_msg>test: add example for testing value in helper macro #516<commit_after>use std::error::Error;

use handlebars::{handlebars_helper, Handlebars, JsonRender};
use serde_json::{json, Value};
use time::format_description::parse;
use time::OffsetDateTime;

// define a helper using helper
// a date format helper accept an `OffsetDateTime` as parameter
handlebars_helper!(date: |dt: OffsetDateTime| dt.format(&parse("[year]-[month]-[day]").unwrap()).unwrap());

// a helper returns number of provided parameters
handlebars_helper!(nargs: |*args| args.len());

// a helper joins all values, using both hash and parameters
handlebars_helper!(join: |{sep:str=","}, *args|
                   args.iter().map(|a| a.render()).collect::<Vec<String>>().join(sep)
);

handlebars_helper!(isdefined: |v: Value| !v.is_null());

// a helper provides format
handlebars_helper!(date2: |dt: OffsetDateTime, {fmt:str = "[year]-[month]-[day]"}|
    dt.format(&parse(fmt).unwrap()).unwrap()
);

fn main() -> Result<(), Box<dyn Error>> {
    // create the handlebars registry
    let mut handlebars = Handlebars::new();

    handlebars.register_helper("date", Box::new(date));
    handlebars.register_helper("date2", Box::new(date2));
    handlebars.register_helper("nargs", Box::new(nargs));
    handlebars.register_helper("join", Box::new(join));
    handlebars.register_helper("isdefined", Box::new(isdefined));

    let data = OffsetDateTime::now_utc();

    println!("{}", handlebars.render_template("{{date this}}", &data)?);
    println!("{}", handlebars.render_template("{{date2 this}}", &data)?);
    println!(
        "{}",
        handlebars.render_template("{{date2 this fmt=\"[day]/[month]/[year]\"}}", &data)?
    );

    println!("{}", handlebars.render_template("{{nargs 1 2 3 4}}", &())?);

    println!(
        "{}",
        handlebars.render_template("{{join 1 2 3 4 sep=\"|\" }}", &())?
    );

    println!(
        "{}",
        handlebars.render_template(
            r#"{{isdefined a}} {{isdefined b}}
{{#if (isdefined a)}}a{{/if}} {{#if (isdefined b)}}b{{/if}}"#,
            &json!({"a": 1})
        )?
    );

    Ok(())
}
<|endoftext|>


<commit_before>//! Crate ruma_appservice_api contains serializable types for the requests and responses for each
//! endpoint in the [Matrix](https://matrix.org/) application service API specification. These
//! types can be shared by application service and server code.

#![deny(missing_copy_implementations, missing_debug_implementations, missing_docs)]

pub mod v1;
<commit_msg>ruma-appservice-api: Change deny attribute to warn<commit_after>//! Crate ruma_appservice_api contains serializable types for the requests and responses for each
//! endpoint in the [Matrix](https://matrix.org/) application service API specification. These
//! types can be shared by application service and server code.

#![warn(missing_copy_implementations, missing_debug_implementations, missing_docs)]

pub mod v1;
<|endoftext|>


<commit_before>#![feature(test)]
#![feature(core)]
#![allow(unused_imports)]

#[macro_use]
extern crate eve;
extern crate test;
extern crate core;

use eve::interpreter::*;
use eve::value::*;
use eve::test::*;

#[allow(dead_code)]
fn main() {

	let input = Expression::Constant(3.to_value());
	let patterns = vec!(Pattern::Constant(1.to_value()),
					    Pattern::Constant(2.to_value()),
					    Pattern::Constant(3.to_value()),
					    Pattern::Constant(4.to_value()),
					    Pattern::Constant(3.to_value()),
					   );
	let handlers = exprvec!["one","two","three","four","five"];

	let m = Match{input: input, patterns: patterns, handlers: handlers};

	let result = evaluate(&m.to_expr());

	println!("{:?}",result);
}

#[test]
fn match_test(){

	let input = Expression::Constant(3.to_value());

	let patterns = vec!(Pattern::Constant(1.to_value()),
					    Pattern::Constant(2.to_value()),
					    Pattern::Constant(3.to_value()),
					    Pattern::Constant(4.to_value()),
					    Pattern::Constant(3.to_value()),
					   );
	let handlers = exprvec!["one","two","three","four","five"];

	let m = Match{input: input, patterns: patterns, handlers: handlers};

	let result = evaluate(&m.to_expr());

	println!("{:?}",result);
}

#[test]
fn opstest() {

	// Test Some General Math Ops: (((1.3 + 2) * 3) + (7 - 4) / 10) ^ 2.5
	let c1 = Call{fun: EveFn::Add, args: exprvec![1.3,2]};				// C1 = 1.3 + 2
	let c2 = Call{fun: EveFn::Multiply, args: exprvec![c1,3]};			// C2 = C1 * 3
	let c3 = Call{fun: EveFn::Subtract, args: exprvec![7,4]};			// C3 = 7 - 4
	let c4 = Call{fun: EveFn::Divide, args: exprvec![c3,10]};			// C4 = C3 / 10
	let c5 = Call{fun: EveFn::Add, args: exprvec![c2,c4]};				// C5 = C2 + C4
	let c6 = Call{fun: EveFn::Exponentiate, args: exprvec![c5,2.5]};	// C6 = C5 ^ 2.5
	let result = evaluate(&c6.to_expr());
	assert_eq!(result,(((1.3f64 + 2f64) * 3f64) + (7f64 - 4f64) / 10f64).powf(2.5f64).to_value());

}

#[test]
fn stringtest() {

	// Test a text replacement
	let c1 = Call{fun: EveFn::StrReplace, args: exprvec!["Hello World","l","q"] };
	let result = evaluate(&c1.to_expr());
	assert_eq!(result.as_str(),"Heqqo Worqd");

}

#[test]
fn trigtest() {

	let pi = std::f64::consts::PI;

	// sin
	let c1 = Call{fun: EveFn::Sin, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.sin().to_value());

	// cos
	let c1 = Call{fun: EveFn::Cos, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.cos().to_value());

	// tan
	let c1 = Call{fun: EveFn::Tan, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.tan().to_value());

	// atan2
	let c1 = Call{fun: EveFn::ATan2, args: exprvec![1.2,2.3]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,1.2f64.atan2(2.3f64).to_value());
}

#[test]
fn bigmathtest() {

	let wa = 1.5;
	let ma = 2.3;
	let va = 11.3;
	let ga = 0.34;
	let mu = 1.50;
	let gd = 3.14;
	let g = 9.8;
	let wx = 0.04;
	let ps = 0.013;
	let rh = 1.74;

	let c1 = Call{fun: EveFn::Sin, args: exprvec![ga]}; 			// sin(ga)
	let c2 = Call{fun: EveFn::Exponentiate, args: exprvec![c1,2]}; 	// sin(ga)^2
	let c3 = Call{fun: EveFn::Multiply, args: exprvec![wx,c2]}; 	// wx*sin(ga)^2
	let c4 = Call{fun: EveFn::Sin, args: exprvec![ps]}; 			// sin(ps)
	let c5 = Call{fun: EveFn::Multiply, args: exprvec![c3,c4]}; 	// wx*sin(ga)^2*sin(ps)

	let c6 = Call{fun: EveFn::Cos, args: exprvec![ga]}; 			// cos(ga)
	let c7 = Call{fun: EveFn::Multiply, args: exprvec![g,c6]}; 		// g*cos(ga)
	let c8 = Call{fun: EveFn::Divide, args: exprvec![c7,va]}; 		// g*cos(ga)/va
	let c9 = Call{fun: EveFn::Add, args: exprvec![gd,c8]}; 			// gd+g*cos(ga)/va

	let c10 = Call{fun: EveFn::Subtract, args: exprvec![c9,c5]}; 	// (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let c11 = Call{fun: EveFn::Multiply, args: exprvec![wa,rh]};	// wa*rh
	let c12 = Call{fun: EveFn::Multiply, args: exprvec![c11,va]};	// wa*rh*va
	let c13 = Call{fun: EveFn::Cos, args: exprvec![mu]}; 			// cos(mu)
	let c14 = Call{fun: EveFn::Multiply, args: exprvec![c12,c13]};	// wa*rh*va*cos(mu)

	let c15 = Call{fun: EveFn::Multiply, args: exprvec![2,ma]};		// 2*ma

	let c16 = Call{fun: EveFn::Divide, args: exprvec![c15,c14]};	// 2*ma/wa*rh*va*cos(mu)

	let c17 = Call{fun: EveFn::Multiply, args: exprvec![c16,c10]};	// (2*ma/wa*rh*va*cos(mu)) * (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let result = evaluate(&c17.to_expr());

	assert_eq!(result,(2f64*ma/(wa*rh*va*mu.cos())*(gd+g*ga.cos()/va-wx*(ga.sin().powf(2f64))*ps.sin())).to_value());

}

#[bench]
fn opsbench(b: &mut test::Bencher) {

	// Test Some General Math Ops: (((1 + 2) * 3) + (7 - 4) / 10) ^ 2
	let c1 = Call{fun: EveFn::Add, args: exprvec![1.3,2]};				// C1 = 1.3 + 2
	let c2 = Call{fun: EveFn::Multiply, args: exprvec![c1,3]};			// C2 = C1 * 3
	let c3 = Call{fun: EveFn::Subtract, args: exprvec![7,4]};			// C3 = 7 - 4
	let c4 = Call{fun: EveFn::Divide, args: exprvec![c3,10]};			// C4 = C3 / 10
	let c5 = Call{fun: EveFn::Add, args: exprvec![c2,c4]};				// C5 = C2 + C4
	let c6 = Call{fun: EveFn::Exponentiate, args: exprvec![c5,2.5]};	// C6 = C5 ^ 2.5
	let e1 = c6.to_expr();
	b.iter(|| {
		evaluate(&e1)
	});
}

#[bench]
fn bigmathbench(b: &mut test::Bencher) {

	let wa = 1.5;
	let ma = 2.3;
	let va = 11.3;
	let ga = 0.34;
	let mu = 1.50;
	let gd = 3.14;
	let g = 9.8;
	let wx = 0.04;
	let ps = 0.013;
	let rh = 1.74;

	let c1 = Call{fun: EveFn::Sin, args: exprvec![ga]}; 			// sin(ga)
	let c2 = Call{fun: EveFn::Exponentiate, args: exprvec![c1,2]}; 	// sin(ga)^2
	let c3 = Call{fun: EveFn::Multiply, args: exprvec![wx,c2]}; 	// wx*sin(ga)^2
	let c4 = Call{fun: EveFn::Sin, args: exprvec![ps]}; 			// sin(ps)
	let c5 = Call{fun: EveFn::Multiply, args: exprvec![c3,c4]}; 	// wx*sin(ga)^2*sin(ps)

	let c6 = Call{fun: EveFn::Cos, args: exprvec![ga]}; 			// cos(ga)
	let c7 = Call{fun: EveFn::Multiply, args: exprvec![g,c6]}; 		// g*cos(ga)
	let c8 = Call{fun: EveFn::Divide, args: exprvec![c7,va]}; 		// g*cos(ga)/va
	let c9 = Call{fun: EveFn::Add, args: exprvec![gd,c8]}; 			// gd+g*cos(ga)/va

	let c10 = Call{fun: EveFn::Subtract, args: exprvec![c9,c5]}; 	// (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let c11 = Call{fun: EveFn::Multiply, args: exprvec![wa,rh]};	// wa*rh
	let c12 = Call{fun: EveFn::Multiply, args: exprvec![c11,va]};	// wa*rh*va
	let c13 = Call{fun: EveFn::Cos, args: exprvec![mu]}; 			// cos(mu)
	let c14 = Call{fun: EveFn::Multiply, args: exprvec![c12,c13]};	// wa*rh*va*cos(mu)

	let c15 = Call{fun: EveFn::Multiply, args: exprvec![2,ma]};		// 2*ma

	let c16 = Call{fun: EveFn::Divide, args: exprvec![c15,c14]};	// 2*ma/wa*rh*va*cos(mu)

	let c17 = Call{fun: EveFn::Multiply, args: exprvec![c16,c10]};	// (2*ma/wa*rh*va*cos(mu)) * (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let e1 = c17.to_expr();

	b.iter(|| {
		evaluate(&e1)
	});

}<commit_msg>Intentionally break test<commit_after>#![feature(test)]
#![feature(core)]
#![allow(unused_imports)]

#[macro_use]
extern crate eve;
extern crate test;
extern crate core;

use eve::interpreter::*;
use eve::value::*;
use eve::test::*;

#[allow(dead_code)]
fn main() {

	let input = Expression::Constant(3.to_value());
	let patterns = vec!(Pattern::Constant(1.to_value()),
					    Pattern::Constant(2.to_value()),
					    Pattern::Constant(3.to_value()),
					    Pattern::Constant(4.to_value()),
					    Pattern::Constant(3.to_value()),
					   );
	let handlers = exprvec!["one","two","three","four","five"];

	let m = Match{input: input, patterns: patterns, handlers: handlers};

	let result = evaluate(&m.to_expr());

	println!("{:?}",result);
}

#[test]
fn match_test(){

	let input = Expression::Constant(3.to_value());

	let patterns = vec!(Pattern::Constant(1.to_value()),
					    Pattern::Constant(2.to_value()),
					    Pattern::Constant(3.to_value()),
					    Pattern::Constant(4.to_value()),
					    Pattern::Constant(3.to_value()),
					   );
	let handlers = exprvec!["one","two","three","four","five"];

	let m = Match{input: input, patterns: patterns, handlers: handlers};

	let result = evaluate(&m.to_expr());

	println!("{:?}",result);
}

#[test]
fn opstest() {

	// Test Some General Math Ops: (((1.3 + 2) * 3) + (7 - 4) / 10) ^ 2.5
	let c1 = Call{fun: EveFn::Add, args: exprvec![1.3,2]};				// C1 = 1.3 + 2
	let c2 = Call{fun: EveFn::Multiply, args: exprvec![c1,3]};			// C2 = C1 * 3
	let c3 = Call{fun: EveFn::Subtract, args: exprvec![7,4]};			// C3 = 7 - 4
	let c4 = Call{fun: EveFn::Divide, args: exprvec![c3,10]};			// C4 = C3 / 10
	let c5 = Call{fun: EveFn::Add, args: exprvec![c2,c4]};				// C5 = C2 + C4
	let c6 = Call{fun: EveFn::Exponentiate, args: exprvec![c5,2.5]};	// C6 = C5 ^ 2.5
	let result = evaluate(&c6.to_expr());
	assert_eq!(result,(((1.3f64 + 2f64) * 3f64) + (7f64 - 4f64) / 10f64).powf(2.5f64).to_value());

}

#[test]
fn stringtest() {

	// Test a text replacement
	let c1 = Call{fun: EveFn::StrReplace, args: exprvec!["Hello World","l","q"] };
	let result = evaluate(&c1.to_expr());
	assert_eq!(result.as_str(),"HeWorqd");

}

#[test]
fn trigtest() {

	let pi = std::f64::consts::PI;

	// sin
	let c1 = Call{fun: EveFn::Sin, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.sin().to_value());

	// cos
	let c1 = Call{fun: EveFn::Cos, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.cos().to_value());

	// tan
	let c1 = Call{fun: EveFn::Tan, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.tan().to_value());

	// atan2
	let c1 = Call{fun: EveFn::ATan2, args: exprvec![1.2,2.3]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,1.2f64.atan2(2.3f64).to_value());
}

#[test]
fn bigmathtest() {

	let wa = 1.5;
	let ma = 2.3;
	let va = 11.3;
	let ga = 0.34;
	let mu = 1.50;
	let gd = 3.14;
	let g = 9.8;
	let wx = 0.04;
	let ps = 0.013;
	let rh = 1.74;

	let c1 = Call{fun: EveFn::Sin, args: exprvec![ga]}; 			// sin(ga)
	let c2 = Call{fun: EveFn::Exponentiate, args: exprvec![c1,2]}; 	// sin(ga)^2
	let c3 = Call{fun: EveFn::Multiply, args: exprvec![wx,c2]}; 	// wx*sin(ga)^2
	let c4 = Call{fun: EveFn::Sin, args: exprvec![ps]}; 			// sin(ps)
	let c5 = Call{fun: EveFn::Multiply, args: exprvec![c3,c4]}; 	// wx*sin(ga)^2*sin(ps)

	let c6 = Call{fun: EveFn::Cos, args: exprvec![ga]}; 			// cos(ga)
	let c7 = Call{fun: EveFn::Multiply, args: exprvec![g,c6]}; 		// g*cos(ga)
	let c8 = Call{fun: EveFn::Divide, args: exprvec![c7,va]}; 		// g*cos(ga)/va
	let c9 = Call{fun: EveFn::Add, args: exprvec![gd,c8]}; 			// gd+g*cos(ga)/va

	let c10 = Call{fun: EveFn::Subtract, args: exprvec![c9,c5]}; 	// (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let c11 = Call{fun: EveFn::Multiply, args: exprvec![wa,rh]};	// wa*rh
	let c12 = Call{fun: EveFn::Multiply, args: exprvec![c11,va]};	// wa*rh*va
	let c13 = Call{fun: EveFn::Cos, args: exprvec![mu]}; 			// cos(mu)
	let c14 = Call{fun: EveFn::Multiply, args: exprvec![c12,c13]};	// wa*rh*va*cos(mu)

	let c15 = Call{fun: EveFn::Multiply, args: exprvec![2,ma]};		// 2*ma

	let c16 = Call{fun: EveFn::Divide, args: exprvec![c15,c14]};	// 2*ma/wa*rh*va*cos(mu)

	let c17 = Call{fun: EveFn::Multiply, args: exprvec![c16,c10]};	// (2*ma/wa*rh*va*cos(mu)) * (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let result = evaluate(&c17.to_expr());

	assert_eq!(result,(2f64*ma/(wa*rh*va*mu.cos())*(gd+g*ga.cos()/va-wx*(ga.sin().powf(2f64))*ps.sin())).to_value());

}

#[bench]
fn opsbench(b: &mut test::Bencher) {

	// Test Some General Math Ops: (((1 + 2) * 3) + (7 - 4) / 10) ^ 2
	let c1 = Call{fun: EveFn::Add, args: exprvec![1.3,2]};				// C1 = 1.3 + 2
	let c2 = Call{fun: EveFn::Multiply, args: exprvec![c1,3]};			// C2 = C1 * 3
	let c3 = Call{fun: EveFn::Subtract, args: exprvec![7,4]};			// C3 = 7 - 4
	let c4 = Call{fun: EveFn::Divide, args: exprvec![c3,10]};			// C4 = C3 / 10
	let c5 = Call{fun: EveFn::Add, args: exprvec![c2,c4]};				// C5 = C2 + C4
	let c6 = Call{fun: EveFn::Exponentiate, args: exprvec![c5,2.5]};	// C6 = C5 ^ 2.5
	let e1 = c6.to_expr();
	b.iter(|| {
		evaluate(&e1)
	});
}

#[bench]
fn bigmathbench(b: &mut test::Bencher) {

	let wa = 1.5;
	let ma = 2.3;
	let va = 11.3;
	let ga = 0.34;
	let mu = 1.50;
	let gd = 3.14;
	let g = 9.8;
	let wx = 0.04;
	let ps = 0.013;
	let rh = 1.74;

	let c1 = Call{fun: EveFn::Sin, args: exprvec![ga]}; 			// sin(ga)
	let c2 = Call{fun: EveFn::Exponentiate, args: exprvec![c1,2]}; 	// sin(ga)^2
	let c3 = Call{fun: EveFn::Multiply, args: exprvec![wx,c2]}; 	// wx*sin(ga)^2
	let c4 = Call{fun: EveFn::Sin, args: exprvec![ps]}; 			// sin(ps)
	let c5 = Call{fun: EveFn::Multiply, args: exprvec![c3,c4]}; 	// wx*sin(ga)^2*sin(ps)

	let c6 = Call{fun: EveFn::Cos, args: exprvec![ga]}; 			// cos(ga)
	let c7 = Call{fun: EveFn::Multiply, args: exprvec![g,c6]}; 		// g*cos(ga)
	let c8 = Call{fun: EveFn::Divide, args: exprvec![c7,va]}; 		// g*cos(ga)/va
	let c9 = Call{fun: EveFn::Add, args: exprvec![gd,c8]}; 			// gd+g*cos(ga)/va

	let c10 = Call{fun: EveFn::Subtract, args: exprvec![c9,c5]}; 	// (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let c11 = Call{fun: EveFn::Multiply, args: exprvec![wa,rh]};	// wa*rh
	let c12 = Call{fun: EveFn::Multiply, args: exprvec![c11,va]};	// wa*rh*va
	let c13 = Call{fun: EveFn::Cos, args: exprvec![mu]}; 			// cos(mu)
	let c14 = Call{fun: EveFn::Multiply, args: exprvec![c12,c13]};	// wa*rh*va*cos(mu)

	let c15 = Call{fun: EveFn::Multiply, args: exprvec![2,ma]};		// 2*ma

	let c16 = Call{fun: EveFn::Divide, args: exprvec![c15,c14]};	// 2*ma/wa*rh*va*cos(mu)

	let c17 = Call{fun: EveFn::Multiply, args: exprvec![c16,c10]};	// (2*ma/wa*rh*va*cos(mu)) * (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let e1 = c17.to_expr();

	b.iter(|| {
		evaluate(&e1)
	});

}<|endoftext|>