<commit_before>use crate::{api::prelude::*, proc_macros::*};

/// The `PopupAction` represent actions that can be sent to `PopupState`.
pub enum PopupAction {
    // placement of the popup relative to its target
    UpdatePlacement,

    // update the visiability status
    UpdateVisibility,
}

/// The `PopupState` handles the open and close behavior of the `Popup` widget.
#[derive(Default, AsAny)]
pub struct PopupState {
    actions: Vec<PopupAction>,
}

impl PopupState {
    /// If the placement property of the popup widget changes, its
    /// bounds will be measured and the rendered widget will be placed
    /// consuming the given position relative to its associated target.
    pub fn update_placement(&mut self) {
        self.actions.push(PopupAction::UpdatePlacement);
    }

    /// the visibility property enables where do we place the popup
    /// widget in relation to the given target.
    pub fn update_visibility(&mut self) {
        self.actions.push(PopupAction::UpdateVisibility);
    }

    // Deprecated: use function layout().
    fn update_placement_internal(&mut self, _registry: &mut Registry, ctx: &mut Context)
    {
        if let Some(target) = ctx.widget().try_clone::<PopupTarget>("target") {

            let current_bounds: Rectangle = ctx.widget().clone("bounds");
            let current_constraint: Constraint = ctx.widget().clone("constraint");

            let real_target_bounds = match target
            {
                PopupTarget::Entity(entity)=>
                {
                    let target_position: Point = ctx.get_widget(entity.into()).clone("position");

                    // WARNING: widget bounds (width an height values)
                    // will be measured as available space for the
                    // widget. Only in `post_layout_update` state it will
                    // reflect the effective size of the given entity.
                    let mut target_bounds: Rectangle = ctx.get_widget(entity.into()).clone("bounds");
                    target_bounds.set_position(target_position);
                    target_bounds
                }
                PopupTarget::Point(mut point)=>
                {
                    point.set_x(point.x()+current_bounds.width()/2.0);
                    point.set_y(point.y()+current_bounds.height()/2.0);
                    Rectangle::new(point,(0.0,0.0))
                }
            };

            let placement: Placement = ctx.widget().clone_or_default("placement");

            let new_popup_bounds = match placement
            {
                Placement::Left(distance)=>
                {
                    let current_v_align: Alignment = ctx.widget().clone("v_align");

                    let x = real_target_bounds.x() - current_bounds.width() - distance;
                    let y = current_v_align.align_position(
                        real_target_bounds.height(),
                        current_bounds.height(),
                        real_target_bounds.y(),
                        real_target_bounds.y()+real_target_bounds.height()
                    );

                    let width = current_bounds.width();
                    let height = current_v_align.align_measure(
                        real_target_bounds.height(),
                        current_bounds.height(),
                        0.0,
                        0.0
                    );

                    Rectangle::new((x,y),current_constraint.perform((width,height)))
                }
                Placement::Right(distance)=>
                {
                    let current_v_align: Alignment = ctx.widget().clone("v_align");

                    let x = real_target_bounds.x() + real_target_bounds.width() + distance;
                    let y = current_v_align.align_position(
                        real_target_bounds.height(),
                        current_bounds.height(),
                        real_target_bounds.y(),
                        real_target_bounds.y()+real_target_bounds.height()
                    );

                    let width = current_bounds.width();
                    let height = current_v_align.align_measure(
                        real_target_bounds.height(),
                        current_bounds.height(),
                        0.0,
                        0.0
                    );

                    Rectangle::new((x,y),current_constraint.perform((width,height)))
                }
                Placement::Top(distance)=>
                {
                    let current_h_align: Alignment = ctx.widget().clone("h_align");

                    let x = current_h_align.align_position(
                        real_target_bounds.width(),
                        current_bounds.width(),
                        real_target_bounds.x(),
                        real_target_bounds.x()+real_target_bounds.width()
                    );
                    let y = real_target_bounds.y() - current_bounds.height() - distance;
                    let width = current_h_align.align_measure(
                        real_target_bounds.width(),
                        current_bounds.width(),
                        0.0,
                        0.0
                    );
                    let height = current_bounds.height();

                    Rectangle::new((x,y),current_constraint.perform((width,height)))
                }
                Placement::Bottom(distance)=>
                {
                    let current_h_align: Alignment = ctx.widget().clone("h_align");

                    let x = current_h_align.align_position(
                        real_target_bounds.width(),
                        current_bounds.width(),
                        real_target_bounds.x(),
                        real_target_bounds.x()+real_target_bounds.width()
                    );
                    let y = real_target_bounds.y() + real_target_bounds.height() + distance;
                    let width = current_h_align.align_measure(
                        real_target_bounds.width(),
                        current_bounds.width(),
                        0.0,
                        0.0
                    );
                    let height = current_bounds.height();

                    Rectangle::new((x,y),current_constraint.perform((width,height)))
                }
            };

            ctx.widget().set::<Rectangle>("bounds",new_popup_bounds);
        }
        else {println!("Target not found");}
    }

    fn update_visibility_internal(&mut self, _registry: &mut Registry, ctx: &mut Context) {
        //if cfg!(feature = "log") {
            println!("popup2: update_visibility_internal: started");
        //}

        let mut widget = ctx.widget();
        let open = widget.clone::<bool>("open");
        let visibility: &mut Visibility = widget.get_mut("visibility");

        //if cfg!(feature = "log") {
            println!("popup2: Current status open: {:?}", open);
            println!("popup2: Current status Visibility: {:?}", visibility);
        //}

        match (open, *visibility) {
            (true, Visibility::Visible) => {}
            (true, Visibility::Hidden) => *visibility = Visibility::Visible,
            (true, Visibility::Collapsed) => *visibility = Visibility::Visible,
            (false, Visibility::Visible) => *visibility = Visibility::Collapsed,
            (false, Visibility::Hidden) => *visibility = Visibility::Collapsed,
            (false, Visibility::Collapsed) => {}
        }

        //if cfg!(feature = "log") {
            println!("popup2: Updated status open: {}", open);
            println!("popup2: Updated status visibility: {:?}", *visibility);
            println!("popup2: update_visibility_internal: finished");
        //}
    }
}

impl State for PopupState {
    fn update(&mut self, registry: &mut Registry, ctx: &mut Context) {
        let actions: Vec<PopupAction> = self.actions.drain(..).collect();
        for action in actions {
            match action {
                PopupAction::UpdatePlacement => self.update_placement_internal(registry,ctx),
                PopupAction::UpdateVisibility => self.update_visibility_internal(registry, ctx),
            }
        }
    }
}

widget!(
    /// The `Popup` is used to presents content bound to target entity.
    ///
    /// The `target` is specified either via its widget id (`Entitiy`)
    /// or using a point coordinate (`Point`). The placmement of the
    /// popup widget itself is controlled via its `placement`
    /// property. An optional distance attribute (float), defines the
    /// margin between the target and the popup widget.
    ///
    /// [`placement`]: ../orbtk_core/render_object/enum.Placement.html
    ///
    /// **style:** `popup``
    Popup<PopupState> : KeyDownHandler, MouseHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the popup open state.
        open: bool,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the placement property relative to the
        /// target position. Valid placement variants are defined via
        /// the `Placement` enumeration.
        placement: Placement,

        /// Sets the target.
        ///
        /// Defined ether as an entity (Entity), or as a point
        /// coordinate (Point).
        target: PopupTarget
    }
);

impl Template for Popup {
    fn template(self, _id: Entity, _: &mut BuildContext) -> Self {
        self.name("Popup")
            .style("popup")
            .open(false)
            //.padding(0.0)
            //.on_mouse_down(|_states, _mouse| true)
            // .on_changed("visibility", move |states, _| {
            //     states.get_mut::<PopupState>(id).update_visibility()
            // })
            //.on_changed("open", move |states, _| {
            //    states.get_mut::<PopupState>(id).update_visibility()
            //})
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(PopupRenderObject::new())
    }

    fn layout(&self) -> Box<dyn Layout> {
        PopupLayout::new().into()
    }
}
<commit_msg>orbtk_widgets: update popup_v2<commit_after>use crate::{api::prelude::*, proc_macros::*};

// Depreciated: use function layout()
// /// The `PopupAction` represent actions that can be sent to `PopupState`.
// pub enum PopupAction {
//     // placement of the popup relative to its target
//     UpdatePlacement,

//     // update the visiability status
//     UpdateVisibility,
// }

/// The `PopupState` handles the open and close behavior of the `Popup` widget.
#[derive(AsAny, Default)]
pub struct PopupState {
    //actions: Vec<PopupAction>,
}

impl PopupState {
    // Depreciated: use function layout()
    // /// If the placement property of the popup widget changes, its
    // /// bounds will be measured and the rendered widget will be placed
    // /// consuming the given position relative to its associated target.
    // pub fn update_placement(&mut self) {
    //	self.actions.push(PopupAction::UpdatePlacement);
    // }

    // Depreciated: use function layout()
    // /// the visibility property enables where do we place the popup
    // /// widget in relation to the given target.
    // pub fn update_visibility(&mut self) {
    //	self.actions.push(PopupAction::UpdateVisibility);
    // }

    // Deprecated: use function layout().
    // fn update_placement_internal(&mut self, _registry: &mut Registry, ctx: &mut Context) {
    //	if let Some(target) = ctx.widget().try_clone::<PopupTarget>("target") {
    //	    let current_bounds: Rectangle = ctx.widget().clone("bounds");
    //	    let current_constraint: Constraint = ctx.widget().clone("constraint");

    //	    let real_target_bounds = match target {
    //		PopupTarget::Entity(entity) => {
    //		    let target_position: Point = ctx.get_widget(entity).clone("position");

    //		    // WARNING: widget bounds (width an height values)
    //		    // will be measured as available space for the
    //		    // widget. Only in `post_layout_update` state it will
    //		    // reflect the effective size of the given entity.
    //		    let mut target_bounds: Rectangle = ctx.get_widget(entity).clone("bounds");
    //		    target_bounds.set_position(target_position);
    //		    target_bounds
    //		}
    //		PopupTarget::Point(mut point) => {
    //		    point.set_x(point.x() + current_bounds.width() / 2.0);
    //		    point.set_y(point.y() + current_bounds.height() / 2.0);
    //		    Rectangle::new(point, (0.0, 0.0))
    //		}
    //	    };

    //	    let placement: Placement = ctx.widget().clone_or_default("placement");

    //	    let new_popup_bounds = match placement {
    //		Placement::Left => {
    //		    let current_v_align: Alignment = ctx.widget().clone("v_align");

    //		    let x = real_target_bounds.x() - current_bounds.width();
    //		    let y = current_v_align.align_position(
    //			real_target_bounds.height(),
    //			current_bounds.height(),
    //			real_target_bounds.y(),
    //			real_target_bounds.y() + real_target_bounds.height(),
    //		    );

    //		    let width = current_bounds.width();
    //		    let height = current_v_align.align_measure(
    //			real_target_bounds.height(),
    //			current_bounds.height(),
    //			0.0,
    //			0.0,
    //		    );

    //		    Rectangle::new((x, y), current_constraint.perform((width, height)))
    //		}
    //		Placement::Right => {
    //		    let current_v_align: Alignment = ctx.widget().clone("v_align");

    //		    let x = real_target_bounds.x() + real_target_bounds.width();
    //		    let y = current_v_align.align_position(
    //			real_target_bounds.height(),
    //			current_bounds.height(),
    //			real_target_bounds.y(),
    //			real_target_bounds.y() + real_target_bounds.height(),
    //		    );

    //		    let width = current_bounds.width();
    //		    let height = current_v_align.align_measure(
    //			real_target_bounds.height(),
    //			current_bounds.height(),
    //			0.0,
    //			0.0,
    //		    );

    //		    Rectangle::new((x, y), current_constraint.perform((width, height)))
    //		}
    //		Placement::Top => {
    //		    let current_h_align: Alignment = ctx.widget().clone("h_align");

    //		    let x = current_h_align.align_position(
    //			real_target_bounds.width(),
    //			current_bounds.width(),
    //			real_target_bounds.x(),
    //			real_target_bounds.x() + real_target_bounds.width(),
    //		    );
    //		    let y = real_target_bounds.y() - current_bounds.height();
    //		    let width = current_h_align.align_measure(
    //			real_target_bounds.width(),
    //			current_bounds.width(),
    //			0.0,
    //			0.0,
    //		    );
    //		    let height = current_bounds.height();

    //		    Rectangle::new((x, y), current_constraint.perform((width, height)))
    //		}
    //		Placement::Bottom => {
    //		    let current_h_align: Alignment = ctx.widget().clone("h_align");

    //		    let x = current_h_align.align_position(
    //			real_target_bounds.width(),
    //			current_bounds.width(),
    //			real_target_bounds.x(),
    //			real_target_bounds.x() + real_target_bounds.width(),
    //		    );
    //		    let y = real_target_bounds.y() + real_target_bounds.height();
    //		    let width = current_h_align.align_measure(
    //			real_target_bounds.width(),
    //			current_bounds.width(),
    //			0.0,
    //			0.0,
    //		    );
    //		    let height = current_bounds.height();

    //		    Rectangle::new((x, y), current_constraint.perform((width, height)))
    //		}
    //	    };

    //	    ctx.widget().set::<Rectangle>("bounds", new_popup_bounds);
    // } else {
    //     println!("Target not found");
    // }
	//}

    // Deprecated: use function layout().
    // fn update_visibility_internal(&mut self, _registry: &mut Registry, ctx: &mut Context) {
    //	//if cfg!(feature = "log") {
    //	println!("popup2: update_visibility_internal: started");
    //	//}

    //	let mut widget = ctx.widget();
    //	let open = widget.clone::<bool>("open");
    //	let visibility: &mut Visibility = widget.get_mut("visibility");

    //	//if cfg!(feature = "log") {
    //	println!("popup2: Current status open: {:?}", open);
    //	println!("popup2: Current status Visibility: {:?}", visibility);
    //	//}

    //	match (open, *visibility) {
    //	    (true, Visibility::Visible) => {}
    //	    (true, Visibility::Hidden) => *visibility = Visibility::Visible,
    //	    (true, Visibility::Collapsed) => *visibility = Visibility::Visible,
    //	    (false, Visibility::Visible) => *visibility = Visibility::Collapsed,
    //	    (false, Visibility::Hidden) => *visibility = Visibility::Collapsed,
    //	    (false, Visibility::Collapsed) => {}
    //	}

    //	//if cfg!(feature = "log") {
    //	println!("popup2: Updated status open: {}", open);
    //	println!("popup2: Updated status visibility: {:?}", *visibility);
    //	println!("popup2: update_visibility_internal: finished");
    //	//}
    // }
}

impl State for PopupState {
    // fn update(&mut self, registry: &mut Registry, ctx: &mut Context) {
    //	let actions: Vec<PopupAction> = self.actions.drain(..).collect();
    //	for action in actions {
    //	    match action {
    //		PopupAction::UpdatePlacement => self.update_placement_internal(registry, ctx),
    //		PopupAction::UpdateVisibility => self.update_visibility_internal(registry, ctx),
    //	    }
    //	}
    // }
}

widget!(
    /// The `Popup` is used to presents content bound to target entity.
    ///
    /// The `target` is specified either via its widget id (`Entitiy`)
    /// or using a point coordinate (`Point`). The placmement of the
    /// popup widget itself is controlled via its `placement`
    /// property. An optional attribute (float), defines the
    /// margin between the target and the popup widget.
    ///
    /// [`placement`]: ../orbtk_core/render_object/enum.Placement.html
    ///
    /// **style:** `popup``
    Popup<PopupState> : KeyDownHandler, MouseHandler {
	/// Sets or shares the background property.
	background: Brush,

	/// Sets or shares the border brush property.
	border_brush: Brush,

	/// Sets or shares the border radius property.
	border_radius: f64,

	/// Sets or shares the border thickness property.
	border_width: Thickness,

	/// Sets or shares the popup open state.
	open: bool,

	/// Sets or shares the padding property.
	padding: Thickness,

	/// Sets or shares the placement property relative to the
	/// target position. Valid placement variants are defined via
	/// the `Placement` enumeration.
	placement: Placement,

	/// Sets or shares the offset property that assignes a margin
	/// between popup and target entity.
	offset: f64,

	///
	/// Defined ether as an entity (Entity), or as a point
	/// coordinate (Point).
	target: PopupTarget
    }
);

impl Template for Popup {
    fn template(self, _id: Entity, _: &mut BuildContext) -> Self {
	self.name("Popup").style("popup").open(false)
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
	Box::new(PopupRenderObject::new())
    }

    fn layout(&self) -> Box<dyn Layout> {
	PopupLayout::new().into()
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Example of mutable string<commit_after>fn main() {
    let mut s = String::new();
}
<|endoftext|>


<commit_before>//! Encode `CreativeWork` nodes to HTML

use super::{
    attr, attr_id, attr_itemprop, attr_itemtype, attr_prop, concat, elem, elem_empty, json,
    EncodeContext, ToHtml,
};
use codec_txt::ToTxt;
use html_escape::encode_safe;
use itertools::Itertools;
use node_transform::Transform;
use std::collections::BTreeMap;
use stencila_schema::*;

impl ToHtml for CreativeWorkTypes {
    fn to_html(&self, context: &EncodeContext) -> String {
        match self {
            CreativeWorkTypes::Article(node) => node.to_html(context),
            CreativeWorkTypes::AudioObject(node) => node.to_html(context),
            CreativeWorkTypes::Claim(node) => node.to_html(context),
            CreativeWorkTypes::Collection(node) => node.to_html(context),
            CreativeWorkTypes::CreativeWork(node) => node.to_html(context),
            CreativeWorkTypes::Figure(node) => node.to_html(context),
            CreativeWorkTypes::ImageObject(node) => node.to_html(context),
            CreativeWorkTypes::Table(node) => node.to_html(context),
            CreativeWorkTypes::VideoObject(node) => node.to_html(context),
            _ => elem("div", &[attr("class", "unsupported")], &json(self)),
        }
    }
}

impl ToHtml for CreativeWorkContent {
    fn to_html(&self, context: &EncodeContext) -> String {
        match self {
            CreativeWorkContent::String(node) => node.to_html(context),
            CreativeWorkContent::VecNode(nodes) => nodes.to_html(context),
        }
    }
}

impl ToHtml for CreativeWork {
    fn to_html(&self, context: &EncodeContext) -> String {
        elem(
            "article",
            &[attr_itemtype::<Self>(), attr_id(&self.id)],
            &self.content.to_html(context),
        )
    }
}

impl ToHtml for Article {
    fn to_html(&self, context: &EncodeContext) -> String {
        let toolbar = elem("stencila-document-toolbar", &[], "");

        let title = match &self.title {
            Some(title) => {
                let title = match &**title {
                    CreativeWorkTitle::String(title) => title.to_html(context),
                    CreativeWorkTitle::VecInlineContent(title) => title.to_html(context),
                };
                elem("h1", &[attr_itemprop("headline")], &title)
            }
            None => "".to_string(),
        };

        // Create a map of organization name to Organization, in the order
        // they appear in affiliations.
        let orgs: BTreeMap<String, &Organization> = match &self.authors {
            Some(authors) => authors
                .iter()
                .filter_map(|author| match author {
                    CreativeWorkAuthors::Person(person) => {
                        person.affiliations.as_ref().map(|orgs| {
                            orgs.iter().filter_map(|org| {
                                org.name.as_ref().map(|name| (*name.clone(), org))
                            })
                        })
                    }
                    _ => None,
                })
                .flatten()
                .collect(),
            None => BTreeMap::new(),
        };
        let orgs = orgs.values().cloned().collect();

        let authors = match &self.authors {
            Some(authors) => {
                let authors = concat(authors, |author| match author {
                    CreativeWorkAuthors::Person(person) => {
                        author_person_to_html(person, Some(&orgs))
                    }
                    CreativeWorkAuthors::Organization(org) => author_org_to_html(org),
                });
                elem("ol", &[attr_prop("authors")], &authors)
            }
            None => "".to_string(),
        };

        let affiliations = if !orgs.is_empty() {
            elem(
                "ol",
                &[attr_prop("affiliations")],
                &concat(&orgs, |org| affiliation_org_to_html(org)),
            )
        } else {
            "".to_string()
        };

        let abstract_ = match &self.description {
            Some(desc) => {
                let meta = (**desc).to_txt();
                let content = match &**desc {
                    ThingDescription::String(string) => Paragraph {
                        content: vec![InlineContent::String(string.clone())],
                        ..Default::default()
                    }
                    .to_html(context),
                    ThingDescription::VecInlineContent(inlines) => Paragraph {
                        content: inlines.clone(),
                        ..Default::default()
                    }
                    .to_html(context),
                    ThingDescription::VecBlockContent(blocks) => blocks.to_html(context),
                };
                elem(
                    "section",
                    &[attr_prop("description")],
                    &[
                        elem_empty(
                            "meta",
                            &[attr_itemprop("description"), attr("content", &meta)],
                        ),
                        content,
                    ]
                    .concat(),
                )
            }
            None => "".to_string(),
        };

        let content = elem(
            "div",
            &[attr_prop("content")],
            &self.content.to_html(context),
        );

        elem(
            "article",
            &[attr_itemtype::<Self>(), attr_id(&self.id)],
            &[toolbar, title, authors, affiliations, abstract_, content].concat(),
        )
    }
}

fn author_person_to_html(person: &Person, orgs: Option<&Vec<&Organization>>) -> String {
    let name_string = if person.given_names.is_some() && person.family_names.is_some() {
        [
            person
                .given_names
                .as_ref()
                .map_or("".to_string(), |vec| vec.join(" ")),
            person
                .family_names
                .as_ref()
                .map_or("".to_string(), |vec| vec.join(" ")),
        ]
        .join(" ")
    } else {
        person
            .name
            .as_ref()
            .map_or("".to_string(), |name| *name.clone())
    };
    let name_string = match name_string.is_empty() {
        true => "Anonymous".to_string(),
        false => name_string,
    };

    // If there are given and/or family names then encode name as invisible `<meta>` tag,
    // otherwise, as a visible `<span>`.
    let name = if person.given_names.is_some() && person.family_names.is_some() {
        #[cfg_attr(rustfmt, rustfmt_skip)]
        [
            "<meta itemprop=\"name\"", &attr("content", &name_string), ">",
        ]
        .concat()
    } else {
        #[cfg_attr(rustfmt, rustfmt_skip)]
        [
            "", &encode_safe(&name_string), "",
        ]
        .concat()
    };

    let given_names = match &person.given_names {
        Some(names) => [
            "",
            &concat(names, |name| {
                ["", name, ""].concat()
            }),
            "",
        ]
        .concat(),
        None => "".to_string(),
    };

    let family_names = match &person.family_names {
        Some(names) => [
            "",
            &concat(names, |name| {
                ["", name, ""].concat()
            }),
            "",
        ]
        .concat(),
        None => "".to_string(),
    };

    let emails = match &person.emails {
        Some(emails) =>
        {
            #[cfg_attr(rustfmt, rustfmt_skip)]
            [
                "",
                &concat(emails, |email| {
                    [
                        "",
                            email,
                        "",
                    ].concat()
                }),
                "",
            ]
            .concat()
        }
        None => "".to_string(),
    };

    let affiliations = if let (Some(affiliations), Some(orgs)) = (&person.affiliations, orgs) {
        #[cfg_attr(rustfmt, rustfmt_skip)]
        [
            "",
            &concat(affiliations, |affiliation| {
                if let Some((index,..)) = orgs.iter().find_position(|org| {
                    org.name == affiliation.name
                }) {
                    let position = (index+1).to_string();
                    [
                        "",
                            &position,
                        ""
                    ].concat()
                } else {
                    "".to_string()
                }
            }),
            ""
        ].concat()
    } else {
        "".to_string()
    };

    #[cfg_attr(rustfmt, rustfmt_skip)]
    [
        "
",
            &name,
            &given_names,
            &family_names,
            &emails,
            &affiliations,
        "
",
    ]
    .concat()
}

fn author_org_to_html(_org: &Organization) -> String {
    [
        "
",
        // TODO
        "
",
    ]
    .concat()
}

fn affiliation_org_to_html(org: &Organization) -> String {
    // TODO Organization address etc
    let name = org
        .name
        .as_ref()
        .map_or("".to_string(), |boxed| *boxed.clone());
    ["
", &name, "
"].concat()
}

/// Generate HTML from the `BlockContent` analogue (e.g. `TableSimple`) or `InlineContent`
/// analogue (e.g. `ImageObjectSimple`) of a creative work type.
/// This is convenience and could be overridden as needed for each type.
macro_rules! to_content_html {
    ($type: ty, $variant: path, $transform:ident) => {
        impl ToHtml for $type {
            fn to_html(&self, context: &EncodeContext) -> String {
                $variant(self.clone()).$transform().to_html(context)
            }
        }
    };
}

to_content_html!(Claim, Node::Claim, to_block);
to_content_html!(Comment, Node::Comment, to_block);
to_content_html!(Collection, Node::Collection, to_block);
to_content_html!(Figure, Node::Figure, to_block);
to_content_html!(Table, Node::Table, to_block);

to_content_html!(AudioObject, Node::AudioObject, to_inline);
to_content_html!(ImageObject, Node::ImageObject, to_inline);
to_content_html!(MediaObject, Node::MediaObject, to_inline);
to_content_html!(VideoObject, Node::VideoObject, to_inline);

// Not yet implemented
impl ToHtml for Periodical {}
impl ToHtml for PublicationIssue {}
impl ToHtml for PublicationVolume {}
impl ToHtml for Review {}
impl ToHtml for SoftwareApplication {}
impl ToHtml for SoftwareSourceCode {}
<commit_msg>fix(HTML Microdata): Add itemtype attribute when encoding Organizations<commit_after>//! Encode `CreativeWork` nodes to HTML

use super::{
    attr, attr_id, attr_itemprop, attr_itemtype, attr_prop, concat, elem, elem_empty, json,
    EncodeContext, ToHtml,
};
use codec_txt::ToTxt;
use html_escape::encode_safe;
use itertools::Itertools;
use node_transform::Transform;
use std::collections::BTreeMap;
use stencila_schema::*;

impl ToHtml for CreativeWorkTypes {
    fn to_html(&self, context: &EncodeContext) -> String {
        match self {
            CreativeWorkTypes::Article(node) => node.to_html(context),
            CreativeWorkTypes::AudioObject(node) => node.to_html(context),
            CreativeWorkTypes::Claim(node) => node.to_html(context),
            CreativeWorkTypes::Collection(node) => node.to_html(context),
            CreativeWorkTypes::CreativeWork(node) => node.to_html(context),
            CreativeWorkTypes::Figure(node) => node.to_html(context),
            CreativeWorkTypes::ImageObject(node) => node.to_html(context),
            CreativeWorkTypes::Table(node) => node.to_html(context),
            CreativeWorkTypes::VideoObject(node) => node.to_html(context),
            _ => elem("div", &[attr("class", "unsupported")], &json(self)),
        }
    }
}

impl ToHtml for CreativeWorkContent {
    fn to_html(&self, context: &EncodeContext) -> String {
        match self {
            CreativeWorkContent::String(node) => node.to_html(context),
            CreativeWorkContent::VecNode(nodes) => nodes.to_html(context),
        }
    }
}

impl ToHtml for CreativeWork {
    fn to_html(&self, context: &EncodeContext) -> String {
        elem(
            "article",
            &[attr_itemtype::<Self>(), attr_id(&self.id)],
            &self.content.to_html(context),
        )
    }
}

impl ToHtml for Article {
    fn to_html(&self, context: &EncodeContext) -> String {
        let toolbar = elem("stencila-document-toolbar", &[], "");

        let title = match &self.title {
            Some(title) => {
                let title = match &**title {
                    CreativeWorkTitle::String(title) => title.to_html(context),
                    CreativeWorkTitle::VecInlineContent(title) => title.to_html(context),
                };
                elem("h1", &[attr_itemprop("headline")], &title)
            }
            None => "".to_string(),
        };

        // Create a map of organization name to Organization, in the order
        // they appear in affiliations.
        let orgs: BTreeMap<String, &Organization> = match &self.authors {
            Some(authors) => authors
                .iter()
                .filter_map(|author| match author {
                    CreativeWorkAuthors::Person(person) => {
                        person.affiliations.as_ref().map(|orgs| {
                            orgs.iter().filter_map(|org| {
                                org.name.as_ref().map(|name| (*name.clone(), org))
                            })
                        })
                    }
                    _ => None,
                })
                .flatten()
                .collect(),
            None => BTreeMap::new(),
        };
        let orgs = orgs.values().cloned().collect();

        let authors = match &self.authors {
            Some(authors) => {
                let authors = concat(authors, |author| match author {
                    CreativeWorkAuthors::Person(person) => {
                        author_person_to_html(person, Some(&orgs))
                    }
                    CreativeWorkAuthors::Organization(org) => author_org_to_html(org),
                });
                elem("ol", &[attr_prop("authors")], &authors)
            }
            None => "".to_string(),
        };

        let affiliations = if !orgs.is_empty() {
            elem(
                "ol",
                &[attr_prop("affiliations")],
                &concat(&orgs, |org| affiliation_org_to_html(org)),
            )
        } else {
            "".to_string()
        };

        let abstract_ = match &self.description {
            Some(desc) => {
                let meta = (**desc).to_txt();
                let content = match &**desc {
                    ThingDescription::String(string) => Paragraph {
                        content: vec![InlineContent::String(string.clone())],
                        ..Default::default()
                    }
                    .to_html(context),
                    ThingDescription::VecInlineContent(inlines) => Paragraph {
                        content: inlines.clone(),
                        ..Default::default()
                    }
                    .to_html(context),
                    ThingDescription::VecBlockContent(blocks) => blocks.to_html(context),
                };
                elem(
                    "section",
                    &[attr_prop("description")],
                    &[
                        elem_empty(
                            "meta",
                            &[attr_itemprop("description"), attr("content", &meta)],
                        ),
                        content,
                    ]
                    .concat(),
                )
            }
            None => "".to_string(),
        };

        let content = elem(
            "div",
            &[attr_prop("content")],
            &self.content.to_html(context),
        );

        elem(
            "article",
            &[attr_itemtype::<Self>(), attr_id(&self.id)],
            &[toolbar, title, authors, affiliations, abstract_, content].concat(),
        )
    }
}

fn author_person_to_html(person: &Person, orgs: Option<&Vec<&Organization>>) -> String {
    let name_string = if person.given_names.is_some() && person.family_names.is_some() {
        [
            person
                .given_names
                .as_ref()
                .map_or("".to_string(), |vec| vec.join(" ")),
            person
                .family_names
                .as_ref()
                .map_or("".to_string(), |vec| vec.join(" ")),
        ]
        .join(" ")
    } else {
        person
            .name
            .as_ref()
            .map_or("".to_string(), |name| *name.clone())
    };
    let name_string = match name_string.is_empty() {
        true => "Anonymous".to_string(),
        false => name_string,
    };

    // If there are given and/or family names then encode name as invisible `<meta>` tag,
    // otherwise, as a visible `<span>`.
    let name = if person.given_names.is_some() && person.family_names.is_some() {
        #[cfg_attr(rustfmt, rustfmt_skip)]
        [
            "<meta itemprop=\"name\"", &attr("content", &name_string), ">",
        ]
        .concat()
    } else {
        #[cfg_attr(rustfmt, rustfmt_skip)]
        [
            "", &encode_safe(&name_string), "",
        ]
        .concat()
    };

    let given_names = match &person.given_names {
        Some(names) => [
            "",
            &concat(names, |name| {
                ["", name, ""].concat()
            }),
            "",
        ]
        .concat(),
        None => "".to_string(),
    };

    let family_names = match &person.family_names {
        Some(names) => [
            "",
            &concat(names, |name| {
                ["", name, ""].concat()
            }),
            "",
        ]
        .concat(),
        None => "".to_string(),
    };

    let emails = match &person.emails {
        Some(emails) =>
        {
            #[cfg_attr(rustfmt, rustfmt_skip)]
            [
                "",
                &concat(emails, |email| {
                    [
                        "",
                            email,
                        "",
                    ].concat()
                }),
                "",
            ]
            .concat()
        }
        None => "".to_string(),
    };

    let affiliations = if let (Some(affiliations), Some(orgs)) = (&person.affiliations, orgs) {
        #[cfg_attr(rustfmt, rustfmt_skip)]
        [
            "",
            &concat(affiliations, |affiliation| {
                if let Some((index,..)) = orgs.iter().find_position(|org| {
                    org.name == affiliation.name
                }) {
                    let position = (index+1).to_string();
                    [
                        "",
                            &position,
                        ""
                    ].concat()
                } else {
                    "".to_string()
                }
            }),
            ""
        ].concat()
    } else {
        "".to_string()
    };

    #[cfg_attr(rustfmt, rustfmt_skip)]
    [
        "
",
            &name,
            &given_names,
            &family_names,
            &emails,
            &affiliations,
        "
",
    ]
    .concat()
}

fn author_org_to_html(_org: &Organization) -> String {
    [
        "
",
        // TODO
        "
",
    ]
    .concat()
}

fn affiliation_org_to_html(org: &Organization) -> String {
    // TODO Organization address etc
    let name = org
        .name
        .as_ref()
        .map_or("".to_string(), |boxed| *boxed.clone());
    [
        "
",
        &name,
        "
"
    ].concat()
}

/// Generate HTML from the `BlockContent` analogue (e.g. `TableSimple`) or `InlineContent`
/// analogue (e.g. `ImageObjectSimple`) of a creative work type.
/// This is convenience and could be overridden as needed for each type.
macro_rules! to_content_html {
    ($type: ty, $variant: path, $transform:ident) => {
        impl ToHtml for $type {
            fn to_html(&self, context: &EncodeContext) -> String {
                $variant(self.clone()).$transform().to_html(context)
            }
        }
    };
}

to_content_html!(Claim, Node::Claim, to_block);
to_content_html!(Comment, Node::Comment, to_block);
to_content_html!(Collection, Node::Collection, to_block);
to_content_html!(Figure, Node::Figure, to_block);
to_content_html!(Table, Node::Table, to_block);

to_content_html!(AudioObject, Node::AudioObject, to_inline);
to_content_html!(ImageObject, Node::ImageObject, to_inline);
to_content_html!(MediaObject, Node::MediaObject, to_inline);
to_content_html!(VideoObject, Node::VideoObject, to_inline);

// Not yet implemented
impl ToHtml for Periodical {}
impl ToHtml for PublicationIssue {}
impl ToHtml for PublicationVolume {}
impl ToHtml for Review {}
impl ToHtml for SoftwareApplication {}
impl ToHtml for SoftwareSourceCode {}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

extern crate filters;
extern crate chrono;
extern crate toml;
extern crate toml_query;
#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate libimagerror;
extern crate libimagstore;
extern crate libimagentrydatetime;
extern crate libimagentrytag;

mod constants;
pub mod error;
pub mod event;
pub mod eventstore;
pub mod iter;
pub mod result;
pub mod tag;

<commit_msg>Add module entry path for library<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

extern crate filters;
extern crate chrono;
extern crate toml;
extern crate toml_query;
#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate libimagerror;
#[macro_use]
extern crate libimagstore;
extern crate libimagentrydatetime;
extern crate libimagentrytag;

mod constants;
pub mod error;
pub mod event;
pub mod eventstore;
pub mod iter;
pub mod result;
pub mod tag;

module_entry_path_mod!("timetrack");

<|endoftext|>


<commit_before>extern crate docopt;
extern crate flexi_logger;
#[macro_use]
extern crate log;
extern crate rustc_serialize;

use docopt::Docopt;
use flexi_logger::{detailed_format,init};
use flexi_logger::LogConfig as FlexiLogConfig;
use rustc_serialize::json;
use std::fs::File;
use std::io::Read;
use std::sync::mpsc::channel;
use std::thread;
use worker::{Request, Response, Item};
use consumer::{StompConfig, StompConsumer, Consumer};
use result_backend::{MysqlConfig, MysqlBackend, ResultBackend, ResultBackendError};
use processor::Processor;

mod consumer;
mod processor;
mod worker;
mod result_backend;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: gworkerd [options] <config>
       gworkerd (--help | --version)

Options:
    -h, --help     Print this information
    -v, --version  Show the version.
";

#[derive(RustcDecodable, Debug)]
struct Args {
	arg_config: String,
	flag_help: bool,
	flag_version: bool,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
struct LogConfig {
	directory: String,
	levels: String
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
struct Config {
	log: LogConfig,
	threads: u32,
	stomp: StompConfig,
	mysql: MysqlConfig,
}

fn main() {
	// docopt
	let args: Args = Docopt::new(USAGE)
		.and_then(|d| d.decode())
		.unwrap_or_else(|e| e.exit());

	let mut file = File::open(args.arg_config).unwrap();
	let mut data = String::new();
	file.read_to_string(&mut data).unwrap();
	let config: Config = json::decode(&data).unwrap();

	init( FlexiLogConfig {
		log_to_file: true,
		directory: Some(config.log.directory.clone()),
		format: detailed_format,
		.. FlexiLogConfig::new()
		},
		Some(config.log.levels.clone())
	).unwrap_or_else(|e|{panic!("Logger initialization failed with {}",e)});

	let mut threads = vec![];
	let (result_backend_tx, result_backend_rx) = channel::<Item>();

	for thread_number in 0..config.threads {
		let stomp_config = config.stomp.clone();
		let thread_tx = result_backend_tx.clone();
		let processor = thread::spawn(move || {
			// connect to message queue
			let stomp_config = stomp_config.clone();
			let mut consumer = StompConsumer::new(&stomp_config);
			{
				let subscription_tx = thread_tx.clone();
				consumer.subscribe(move |request: Request| {
					info!("Executing {} for cwd {}", request.command, request.cwd);

					let response : Response = Processor::run(request.clone());

					info!("received status: {:?}", &response.status);
					debug!("received from stdout: {:?}", &response.stdout);
					debug!("received from stderr: {:?}", &response.stderr);

					let item = worker::Item { request: request.clone(), response: response };
					subscription_tx.send(item.clone()).unwrap();
				});
			}
			consumer.listen();
			info!("started session {:?}", thread_number);
		});
		threads.push(processor);
	}

	let result_backend = thread::spawn(move || {
		let connection = MysqlBackend::new(&config.mysql);
		loop {
			let item = result_backend_rx.recv().unwrap();
			match connection.store(&item) {
				Err(ResultBackendError::CannotStoreResult) => {
					error!("cannot add {:?} to result backend", item);
				},
				Ok(_) => {
					info!("added {:?} to result backend", item.request.id);
				}
			}

		}
	});

	for item in threads {
		item.join().ok().expect("unable to join processor thread");
	}

	result_backend.join().ok().expect("unable to join result backend thread");
}<commit_msg>improve logging, prepend id of the command to each log statement<commit_after>extern crate docopt;
extern crate flexi_logger;
#[macro_use]
extern crate log;
extern crate rustc_serialize;

use docopt::Docopt;
use flexi_logger::{detailed_format,init};
use flexi_logger::LogConfig as FlexiLogConfig;
use rustc_serialize::json;
use std::fs::File;
use std::io::Read;
use std::sync::mpsc::channel;
use std::thread;
use worker::{Request, Response, Item};
use consumer::{StompConfig, StompConsumer, Consumer};
use result_backend::{MysqlConfig, MysqlBackend, ResultBackend, ResultBackendError};
use processor::Processor;

mod consumer;
mod processor;
mod worker;
mod result_backend;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: gworkerd [options] <config>
       gworkerd (--help | --version)

Options:
    -h, --help     Print this information
    -v, --version  Show the version.
";

#[derive(RustcDecodable, Debug)]
struct Args {
	arg_config: String,
	flag_help: bool,
	flag_version: bool,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
struct LogConfig {
	directory: String,
	levels: String
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
struct Config {
	log: LogConfig,
	threads: u32,
	stomp: StompConfig,
	mysql: MysqlConfig,
}

fn main() {
	// docopt
	let args: Args = Docopt::new(USAGE)
		.and_then(|d| d.decode())
		.unwrap_or_else(|e| e.exit());

	let mut file = File::open(args.arg_config).unwrap();
	let mut data = String::new();
	file.read_to_string(&mut data).unwrap();
	let config: Config = json::decode(&data).unwrap();

	init( FlexiLogConfig {
		log_to_file: true,
		directory: Some(config.log.directory.clone()),
		format: detailed_format,
		.. FlexiLogConfig::new()
		},
		Some(config.log.levels.clone())
	).unwrap_or_else(|e|{panic!("Logger initialization failed with {}",e)});

	let mut threads = vec![];
	let (result_backend_tx, result_backend_rx) = channel::<Item>();

	for thread_number in 0..config.threads {
		let stomp_config = config.stomp.clone();
		let thread_tx = result_backend_tx.clone();
		let processor = thread::spawn(move || {
			// connect to message queue
			let stomp_config = stomp_config.clone();
			let mut consumer = StompConsumer::new(&stomp_config);
			{
				let subscription_tx = thread_tx.clone();
				consumer.subscribe(move |request: Request| {
					info!("[{:?}] executing {} in cwd {}", request.id, request.command, request.cwd);

					let response : Response = Processor::run(request.clone());

					info!("[{:?}] finished with status: {:?}", request.id, response.status);
					debug!("[{:?}] finished with stdout: {:?}", request.id, response.stdout);
					debug!("[{:?}] finished with stderr: {:?}", request.id, response.stderr);

					let item = worker::Item { request: request.clone(), response: response };
					subscription_tx.send(item.clone()).unwrap();
				});
			}
			info!("start listening for thread {:?}", thread_number);
			consumer.listen();
		});
		threads.push(processor);
	}

	let result_backend = thread::spawn(move || {
		let connection = MysqlBackend::new(&config.mysql);
		loop {
			let item = result_backend_rx.recv().unwrap();
			match connection.store(&item) {
				Err(ResultBackendError::CannotStoreResult) => {
					error!("[{:?}] cannot add to result backend", item.request.id);
				},
				Ok(_) => {
					info!("[{:?}] added to result backend", item.request.id);
				}
			}

		}
	});

	for item in threads {
		item.join().ok().expect("unable to join processor thread");
	}

	result_backend.join().ok().expect("unable to join result backend thread");
}<|endoftext|>


<commit_before>//! Snapshot testing library, see
//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
use std::{
    collections::HashMap,
    env, fmt, fs,
    ops::Range,
    path::{Path, PathBuf},
    sync::Mutex,
};

use once_cell::sync::Lazy;
use stdx::{lines_with_ends, trim_indent};

const HELP: &str = "
You can update all `expect![[]]` tests by:

    env UPDATE_EXPECT=1 cargo test

To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
";

fn update_expect() -> bool {
    env::var("UPDATE_EXPECT").is_ok()
}

/// expect![[""]]
#[macro_export]
macro_rules! expect {
    [[$lit:literal]] => {$crate::Expect {
        file: file!(),
        line: line!(),
        column: column!(),
        data: $lit,
    }};
    [[]] => { $crate::expect![[""]] };
}

#[derive(Debug)]
pub struct Expect {
    pub file: &'static str,
    pub line: u32,
    pub column: u32,
    pub data: &'static str,
}

impl Expect {
    pub fn assert_eq(&self, actual: &str) {
        let trimmed = self.trimmed();
        if &trimmed == actual {
            return;
        }
        Runtime::fail(self, &trimmed, actual);
    }
    pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
        let actual = format!("{:#?}\n", actual);
        self.assert_eq(&actual)
    }

    fn trimmed(&self) -> String {
        if !self.data.contains('\n') {
            return self.data.to_string();
        }
        trim_indent(self.data)
    }

    fn locate(&self, file: &str) -> Location {
        let mut target_line = None;
        let mut line_start = 0;
        for (i, line) in lines_with_ends(file).enumerate() {
            if i == self.line as usize - 1 {
                let pat = "expect![[";
                let offset = line.find(pat).unwrap();
                let literal_start = line_start + offset + pat.len();
                let indent = line.chars().take_while(|&it| it == ' ').count();
                target_line = Some((literal_start, indent));
                break;
            }
            line_start += line.len();
        }
        let (literal_start, line_indent) = target_line.unwrap();
        let literal_length =
            file[literal_start..].find("]]").expect("Couldn't find matching `]]` for `expect![[`.");
        let literal_range = literal_start..literal_start + literal_length;
        Location { line_indent, literal_range }
    }
}

#[derive(Default)]
struct Runtime {
    help_printed: bool,
    per_file: HashMap<&'static str, FileRuntime>,
}
static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);

impl Runtime {
    fn fail(expect: &Expect, expected: &str, actual: &str) {
        let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
        let mut updated = "";
        if update_expect() {
            updated = " (updated)";
            rt.per_file
                .entry(expect.file)
                .or_insert_with(|| FileRuntime::new(expect))
                .update(expect, actual);
        }
        let print_help = !rt.help_printed && !update_expect();
        rt.help_printed = true;

        let help = if print_help { HELP } else { "" };

        let diff = difference::Changeset::new(actual, expected, "\n");

        println!(
            "\n
\x1b[1m\x1b[91merror\x1b[97m: expect test failed\x1b[0m{}
   \x1b[1m\x1b[34m-->\x1b[0m {}:{}:{}
{}
\x1b[1mExpect\x1b[0m:
----
{}
----

\x1b[1mActual\x1b[0m:
----
{}
----

\x1b[1mDiff\x1b[0m:
----
{}
----
",
            updated, expect.file, expect.line, expect.column, help, expected, actual, diff
        );
        // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
        std::panic::resume_unwind(Box::new(()));
    }
}

struct FileRuntime {
    path: PathBuf,
    original_text: String,
    patchwork: Patchwork,
}

impl FileRuntime {
    fn new(expect: &Expect) -> FileRuntime {
        let path = workspace_root().join(expect.file);
        let original_text = fs::read_to_string(&path).unwrap();
        let patchwork = Patchwork::new(original_text.clone());
        FileRuntime { path, original_text, patchwork }
    }
    fn update(&mut self, expect: &Expect, actual: &str) {
        let loc = expect.locate(&self.original_text);
        let patch = format_patch(loc.line_indent.clone(), actual);
        self.patchwork.patch(loc.literal_range, &patch);
        fs::write(&self.path, &self.patchwork.text).unwrap()
    }
}

#[derive(Debug)]
struct Location {
    line_indent: usize,
    literal_range: Range<usize>,
}

#[derive(Debug)]
struct Patchwork {
    text: String,
    indels: Vec<(Range<usize>, usize)>,
}

impl Patchwork {
    fn new(text: String) -> Patchwork {
        Patchwork { text, indels: Vec::new() }
    }
    fn patch(&mut self, mut range: Range<usize>, patch: &str) {
        self.indels.push((range.clone(), patch.len()));
        self.indels.sort_by_key(|(delete, _insert)| delete.start);

        let (delete, insert) = self
            .indels
            .iter()
            .take_while(|(delete, _)| delete.start < range.start)
            .map(|(delete, insert)| (delete.end - delete.start, insert))
            .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));

        for pos in &mut [&mut range.start, &mut range.end] {
            **pos += insert;
            **pos -= delete
        }

        self.text.replace_range(range, &patch);
    }
}

fn format_patch(line_indent: usize, patch: &str) -> String {
    let mut max_hashes = 0;
    let mut cur_hashes = 0;
    for byte in patch.bytes() {
        if byte != b'#' {
            cur_hashes = 0;
            continue;
        }
        cur_hashes += 1;
        max_hashes = max_hashes.max(cur_hashes);
    }
    let hashes = &"#".repeat(max_hashes + 1);
    let indent = &" ".repeat(line_indent);
    let is_multiline = patch.contains('\n');

    let mut buf = String::new();
    buf.push('r');
    buf.push_str(hashes);
    buf.push('"');
    if is_multiline {
        buf.push('\n');
    }
    let mut final_newline = false;
    for line in lines_with_ends(patch) {
        if is_multiline {
            buf.push_str(indent);
            buf.push_str("    ");
        }
        buf.push_str(line);
        final_newline = line.ends_with('\n');
    }
    if final_newline {
        buf.push_str(indent);
    }
    buf.push('"');
    buf.push_str(hashes);
    buf
}

fn workspace_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(2)
    .unwrap()
    .to_path_buf()
}

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

    #[test]
    fn test_format_patch() {
        let patch = format_patch(0, "hello\nworld\n");
        expect![[r##"
            r#"
                hello
                world
            "#"##]]
        .assert_eq(&patch);

        let patch = format_patch(4, "single line");
        expect![[r##"r#"single line"#"##]].assert_eq(&patch);
    }

    #[test]
    fn test_patchwork() {
        let mut patchwork = Patchwork::new("one two three".to_string());
        patchwork.patch(4..7, "zwei");
        patchwork.patch(0..3, "один");
        patchwork.patch(8..13, "3");
        expect![[r#"
            Patchwork {
                text: "один zwei 3",
                indels: [
                    (
                        0..3,
                        8,
                    ),
                    (
                        4..7,
                        4,
                    ),
                    (
                        8..13,
                        1,
                    ),
                ],
            }
        "#]]
        .assert_debug_eq(&patchwork);
    }
}
<commit_msg>style<commit_after>//! Snapshot testing library, see
//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
use std::{
    collections::HashMap,
    env, fmt, fs,
    ops::Range,
    panic,
    path::{Path, PathBuf},
    sync::Mutex,
};

use difference::Changeset;
use once_cell::sync::Lazy;
use stdx::{lines_with_ends, trim_indent};

const HELP: &str = "
You can update all `expect![[]]` tests by:

    env UPDATE_EXPECT=1 cargo test

To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
";

fn update_expect() -> bool {
    env::var("UPDATE_EXPECT").is_ok()
}

/// expect![[""]]
#[macro_export]
macro_rules! expect {
    [[$lit:literal]] => {$crate::Expect {
        file: file!(),
        line: line!(),
        column: column!(),
        data: $lit,
    }};
    [[]] => { $crate::expect![[""]] };
}

#[derive(Debug)]
pub struct Expect {
    pub file: &'static str,
    pub line: u32,
    pub column: u32,
    pub data: &'static str,
}

impl Expect {
    pub fn assert_eq(&self, actual: &str) {
        let trimmed = self.trimmed();
        if &trimmed == actual {
            return;
        }
        Runtime::fail(self, &trimmed, actual);
    }
    pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
        let actual = format!("{:#?}\n", actual);
        self.assert_eq(&actual)
    }

    fn trimmed(&self) -> String {
        if !self.data.contains('\n') {
            return self.data.to_string();
        }
        trim_indent(self.data)
    }

    fn locate(&self, file: &str) -> Location {
        let mut target_line = None;
        let mut line_start = 0;
        for (i, line) in lines_with_ends(file).enumerate() {
            if i == self.line as usize - 1 {
                let pat = "expect![[";
                let offset = line.find(pat).unwrap();
                let literal_start = line_start + offset + pat.len();
                let indent = line.chars().take_while(|&it| it == ' ').count();
                target_line = Some((literal_start, indent));
                break;
            }
            line_start += line.len();
        }
        let (literal_start, line_indent) = target_line.unwrap();
        let literal_length =
            file[literal_start..].find("]]").expect("Couldn't find matching `]]` for `expect![[`.");
        let literal_range = literal_start..literal_start + literal_length;
        Location { line_indent, literal_range }
    }
}

#[derive(Default)]
struct Runtime {
    help_printed: bool,
    per_file: HashMap<&'static str, FileRuntime>,
}
static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);

impl Runtime {
    fn fail(expect: &Expect, expected: &str, actual: &str) {
        let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
        let mut updated = "";
        if update_expect() {
            updated = " (updated)";
            rt.per_file
                .entry(expect.file)
                .or_insert_with(|| FileRuntime::new(expect))
                .update(expect, actual);
        }
        let print_help = !rt.help_printed && !update_expect();
        rt.help_printed = true;

        let help = if print_help { HELP } else { "" };

        let diff = Changeset::new(actual, expected, "\n");

        println!(
            "\n
\x1b[1m\x1b[91merror\x1b[97m: expect test failed\x1b[0m{}
   \x1b[1m\x1b[34m-->\x1b[0m {}:{}:{}
{}
\x1b[1mExpect\x1b[0m:
----
{}
----

\x1b[1mActual\x1b[0m:
----
{}
----

\x1b[1mDiff\x1b[0m:
----
{}
----
",
            updated, expect.file, expect.line, expect.column, help, expected, actual, diff
        );
        // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
        panic::resume_unwind(Box::new(()));
    }
}

struct FileRuntime {
    path: PathBuf,
    original_text: String,
    patchwork: Patchwork,
}

impl FileRuntime {
    fn new(expect: &Expect) -> FileRuntime {
        let path = workspace_root().join(expect.file);
        let original_text = fs::read_to_string(&path).unwrap();
        let patchwork = Patchwork::new(original_text.clone());
        FileRuntime { path, original_text, patchwork }
    }
    fn update(&mut self, expect: &Expect, actual: &str) {
        let loc = expect.locate(&self.original_text);
        let patch = format_patch(loc.line_indent.clone(), actual);
        self.patchwork.patch(loc.literal_range, &patch);
        fs::write(&self.path, &self.patchwork.text).unwrap()
    }
}

#[derive(Debug)]
struct Location {
    line_indent: usize,
    literal_range: Range<usize>,
}

#[derive(Debug)]
struct Patchwork {
    text: String,
    indels: Vec<(Range<usize>, usize)>,
}

impl Patchwork {
    fn new(text: String) -> Patchwork {
        Patchwork { text, indels: Vec::new() }
    }
    fn patch(&mut self, mut range: Range<usize>, patch: &str) {
        self.indels.push((range.clone(), patch.len()));
        self.indels.sort_by_key(|(delete, _insert)| delete.start);

        let (delete, insert) = self
            .indels
            .iter()
            .take_while(|(delete, _)| delete.start < range.start)
            .map(|(delete, insert)| (delete.end - delete.start, insert))
            .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));

        for pos in &mut [&mut range.start, &mut range.end] {
            **pos += insert;
            **pos -= delete
        }

        self.text.replace_range(range, &patch);
    }
}

fn format_patch(line_indent: usize, patch: &str) -> String {
    let mut max_hashes = 0;
    let mut cur_hashes = 0;
    for byte in patch.bytes() {
        if byte != b'#' {
            cur_hashes = 0;
            continue;
        }
        cur_hashes += 1;
        max_hashes = max_hashes.max(cur_hashes);
    }
    let hashes = &"#".repeat(max_hashes + 1);
    let indent = &" ".repeat(line_indent);
    let is_multiline = patch.contains('\n');

    let mut buf = String::new();
    buf.push('r');
    buf.push_str(hashes);
    buf.push('"');
    if is_multiline {
        buf.push('\n');
    }
    let mut final_newline = false;
    for line in lines_with_ends(patch) {
        if is_multiline {
            buf.push_str(indent);
            buf.push_str("    ");
        }
        buf.push_str(line);
        final_newline = line.ends_with('\n');
    }
    if final_newline {
        buf.push_str(indent);
    }
    buf.push('"');
    buf.push_str(hashes);
    buf
}

fn workspace_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(2)
    .unwrap()
    .to_path_buf()
}

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

    #[test]
    fn test_format_patch() {
        let patch = format_patch(0, "hello\nworld\n");
        expect![[r##"
            r#"
                hello
                world
            "#"##]]
        .assert_eq(&patch);

        let patch = format_patch(4, "single line");
        expect![[r##"r#"single line"#"##]].assert_eq(&patch);
    }

    #[test]
    fn test_patchwork() {
        let mut patchwork = Patchwork::new("one two three".to_string());
        patchwork.patch(4..7, "zwei");
        patchwork.patch(0..3, "один");
        patchwork.patch(8..13, "3");
        expect![[r#"
            Patchwork {
                text: "один zwei 3",
                indels: [
                    (
                        0..3,
                        8,
                    ),
                    (
                        4..7,
                        4,
                    ),
                    (
                        8..13,
                        1,
                    ),
                ],
            }
        "#]]
        .assert_debug_eq(&patchwork);
    }
}
<|endoftext|>


<commit_before>#[allow(ctypes)];
#[no_std];
//#[no_core];
#[feature(macro_rules)];
use super::core::mem;
/* Defines an IDT entry */
struct IDTEntry {
    base_lo: u16,
    sel: u16,        /* Our kernel segment goes here! */
    zero: u8,        /* This will ALWAYS be set to 0! */
    flags: u8,       /* Set using the above table! */
    base_hi: u16
}

/* Defines an IDT pointer */
struct IDTPointer {
    limit: u16,
    base: u32
}

/* Declare an IDT of 256 entries. Although we will only use the
 *  first 32 entries in this tutorial, the rest exists as a bit
 *  of a trap. If any undefined IDT entry is hit, it normally
 *  will cause an "Unhandled Interrupt" exception. Any descriptor
 *  for which the 'presence' bit is cleared (0) will generate an
 *  "Unhandled Interrupt" exception */

#[no_mangle]
static mut idt: [IDTEntry, ..256] = [IDTEntry {base_lo: 0, sel: 0, zero: 0, flags: 0, base_hi: 0}, ..256];

#[no_mangle]
pub static mut idtp: IDTPointer = IDTPointer {limit: 0, base: 0};

/* Use this function to set an entry in the IDT. A lot simpler
*  than twiddling with the GDT ;) */
#[no_mangle]
unsafe fn idt_set_gate(num: u8, base: u32, sel: u16, flags: u8)
{
    idt[num].sel = sel;
    idt[num].flags = flags;
    idt[num].base_hi = (base >> 16) as u16;
    idt[num].base_lo = (base & (1 << 16 - 1)) as u16;
}

/* Installs the IDT */
extern {
    fn idt_load(x: *IDTPointer);
}

#[no_mangle]
pub unsafe fn idt_install() {
    /* Sets the special IDT pointer up, just like in 'gdt.c' */
    idtp.limit = ((super::core::mem::size_of::<IDTEntry>() * 256) - 1) as u16;
    idtp.base = &idt as *[IDTEntry, ..256] as u32;

    /* Add any new ISRs to the IDT here using idt_set_gate */
    //asm!("lidt (%0)" : :"p" ())

    /* Points the processor's internal register to the new IDT */
    idt_load(&idtp as *IDTPointer);
}

<commit_msg>Improve idt_set_gate function signature<commit_after>#[allow(ctypes)];
#[no_std];
//#[no_core];
#[feature(macro_rules)];
use super::core::mem;
/* Defines an IDT entry */
struct IDTEntry {
    base_lo: u16,
    sel: u16,        /* Our kernel segment goes here! */
    zero: u8,        /* This will ALWAYS be set to 0! */
    flags: u8,       /* Set using the above table! */
    base_hi: u16
}

/* Defines an IDT pointer */
struct IDTPointer {
    limit: u16,
    base: u32
}

/* Declare an IDT of 256 entries. Although we will only use the
 *  first 32 entries in this tutorial, the rest exists as a bit
 *  of a trap. If any undefined IDT entry is hit, it normally
 *  will cause an "Unhandled Interrupt" exception. Any descriptor
 *  for which the 'presence' bit is cleared (0) will generate an
 *  "Unhandled Interrupt" exception */

#[no_mangle]
static mut idt: [IDTEntry, ..256] = [IDTEntry {base_lo: 0, sel: 0, zero: 0, flags: 0, base_hi: 0}, ..256];

#[no_mangle]
pub static mut idtp: IDTPointer = IDTPointer {limit: 0, base: 0};

/* Use this function to set an entry in the IDT. A lot simpler
*  than twiddling with the GDT ;) */
#[no_mangle]
unsafe fn idt_set_gate(num: u8, f: extern "C" fn(), sel: u16, flags: u8)
{

    let base = f as u32;
    idt[num].sel = sel;
    idt[num].flags = flags;
    idt[num].base_hi = (base >> 16) as u16;
    idt[num].base_lo = (base & (1 << 16 - 1)) as u16;
}

/* Installs the IDT */
extern {
    fn idt_load(x: *IDTPointer);
}

#[no_mangle]
pub unsafe fn idt_install() {
    idt_load(&idtp as *IDTPointer);
    /* Sets the special IDT pointer up, just like in 'gdt.c' */
    idtp.limit = ((super::core::mem::size_of::<IDTEntry>() * 256) - 1) as u16;
    idtp.base = &idt as *[IDTEntry, ..256] as u32;

    /* Add any new ISRs to the IDT here using idt_set_gate */
//    idt_set_gate();
    //asm!("lidt (%0)" : :"p" ())

    /* Points the processor's internal register to the new IDT */
}

<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::{bail, Result};
use structopt::StructOpt;

use bytecode::function_target_pipeline::{FunctionTargetPipeline, FunctionTargetsHolder};
use move_binary_format::errors::{Location, PartialVMError, VMResult};
use move_core_types::{
    account_address::AccountAddress,
    identifier::{IdentStr, Identifier},
    language_storage::{ModuleId, TypeTag},
    parser::{parse_transaction_argument, parse_type_tag},
    transaction_argument::TransactionArgument,
    value::{MoveStruct, MoveValue},
    vm_status::StatusCode,
};
use move_model::model::{FunctionEnv, GlobalEnv};

mod concrete;
mod shared;

use crate::concrete::{
    runtime::Runtime,
    ty::{BaseType, IntType, PrimitiveType},
    value::{BaseValue, GlobalState, TypedValue},
};

/// Options passed into the interpreter generator.
#[derive(StructOpt)]
pub struct InterpreterOptions {
    /// The function to be executed, specified in the format of `addr::module_name::function_name`
    #[structopt(long = "entry", parse(try_from_str = parse_entrypoint))]
    pub entrypoint: (ModuleId, Identifier),

    /// Possibly-empty list of signers for the execution
    #[structopt(long = "signers", parse(try_from_str = AccountAddress::from_hex_literal))]
    pub signers: Vec<AccountAddress>,
    /// Possibly-empty list of arguments passed to the transaction
    #[structopt(long = "args", parse(try_from_str = parse_transaction_argument))]
    pub args: Vec<TransactionArgument>,
    /// Possibly-empty list of type arguments passed to the transaction (e.g., `T` in
    /// `main<T>()`). Must match the type arguments kinds expected by `script_file`.
    #[structopt(long = "ty-args", parse(try_from_str = parse_type_tag))]
    pub ty_args: Vec<TypeTag>,

    /// Print verbose debug information
    #[structopt(short = "v", long = "verbose")]
    pub verbose: bool,
}

fn parse_entrypoint(input: &str) -> Result<(ModuleId, Identifier)> {
    let tokens: Vec<_> = input.split("::").collect();
    if tokens.len() != 3 {
        bail!("Invalid entrypoint: {}", input);
    }
    let module_id = ModuleId::new(
        AccountAddress::from_hex_literal(tokens[0])?,
        Identifier::new(tokens[1])?,
    );
    let func_name = Identifier::new(tokens[2])?;
    Ok((module_id, func_name))
}

#[derive(Debug, Eq, PartialEq)]
struct ExecutionResult {
    vm_result: VMResult<Vec<TypedValue>>,
    global_state: GlobalState,
}

//**************************************************************************************************
// Entry
//**************************************************************************************************
pub fn interpret_with_options(
    options: InterpreterOptions,
    env: &GlobalEnv,
    pipeline: FunctionTargetPipeline,
) -> VMResult<Vec<Vec<u8>>> {
    // consolidate arguments
    let args: Vec<_> = options
        .signers
        .into_iter()
        .map(MoveValue::Signer)
        .chain(options.args.into_iter().map(|arg| match arg {
            TransactionArgument::Bool(v) => MoveValue::Bool(v),
            TransactionArgument::U8(v) => MoveValue::U8(v),
            TransactionArgument::U64(v) => MoveValue::U64(v),
            TransactionArgument::U128(v) => MoveValue::U128(v),
            TransactionArgument::Address(v) => MoveValue::Address(v),
            TransactionArgument::U8Vector(v) => {
                MoveValue::Vector(v.into_iter().map(MoveValue::U8).collect())
            }
        }))
        .collect();

    // run the actual interpreter
    interpret(
        env,
        &options.entrypoint.0,
        &options.entrypoint.1,
        &options.ty_args,
        &args,
        pipeline,
        options.verbose,
    )
}

pub fn interpret(
    env: &GlobalEnv,
    module_id: &ModuleId,
    func_name: &IdentStr,
    ty_args: &[TypeTag],
    args: &[MoveValue],
    pipeline: FunctionTargetPipeline,
    verbose: bool,
) -> VMResult<Vec<Vec<u8>>> {
    // find the entrypoint
    let entrypoint_env = env
        .find_module_by_language_storage_id(module_id)
        .and_then(|module_env| module_env.find_function(env.symbol_pool().make(func_name.as_str())))
        .ok_or_else(|| {
            PartialVMError::new(StatusCode::LOOKUP_FAILED).finish(Location::Undefined)
        })?;
    if verbose {
        println!(
            "[compiled module]\n{:?}\n",
            entrypoint_env.module_env.get_verified_module()
        );
    }

    // collect and transform function targets
    let mut targets = FunctionTargetsHolder::default();
    for module_env in env.get_modules() {
        for func_env in module_env.get_functions() {
            targets.add_target(&func_env)
        }
    }
    pipeline.run(env, &mut targets);

    // execute and convert results
    let (vm_result, _) = interpret_internal(env, &targets, &entrypoint_env, ty_args, args, verbose);
    vm_result.map(|rets| {
        rets.into_iter()
            .map(|v| {
                let (ty, val, _) = v.decompose();
                let move_val = convert_typed_value_to_move_value(ty.get_base_type(), val);
                move_val.simple_serialize().unwrap()
            })
            .collect::<Vec<_>>()
    })
}

fn interpret_internal(
    env: &GlobalEnv,
    targets: &FunctionTargetsHolder,
    fun_env: &FunctionEnv,
    ty_args: &[TypeTag],
    args: &[MoveValue],
    verbose: bool,
) -> (VMResult<Vec<TypedValue>>, GlobalState) {
    // dump the bytecode if requested
    if verbose {
        let mut text = String::new();
        for module_env in env.get_modules() {
            for func_env in module_env.get_functions() {
                for (variant, target) in targets.get_targets(&func_env) {
                    target.register_annotation_formatters_for_test();
                    text += &format!("[variant {}]\n{}\n", variant, target);
                }
            }
        }
        println!("{}", text);
    }

    // invoke the runtime
    let vm = Runtime::new(env, targets);
    let global_state = GlobalState::default();
    vm.execute(fun_env, ty_args, args, global_state)
}

fn convert_typed_value_to_move_value(ty: &BaseType, val: BaseValue) -> MoveValue {
    match ty {
        BaseType::Primitive(PrimitiveType::Bool) => MoveValue::Bool(val.into_bool()),
        BaseType::Primitive(PrimitiveType::Int(IntType::U8)) => MoveValue::U8(val.into_u8()),
        BaseType::Primitive(PrimitiveType::Int(IntType::U64)) => MoveValue::U64(val.into_u64()),
        BaseType::Primitive(PrimitiveType::Int(IntType::U128)) => MoveValue::U128(val.into_u128()),
        BaseType::Primitive(PrimitiveType::Int(IntType::Num)) => unreachable!(),
        BaseType::Primitive(PrimitiveType::Address) => MoveValue::Address(val.into_address()),
        BaseType::Primitive(PrimitiveType::Signer) => MoveValue::Signer(val.into_signer()),
        BaseType::Vector(elem) => MoveValue::Vector(
            val.into_vector()
                .into_iter()
                .map(|e| convert_typed_value_to_move_value(elem, e))
                .collect(),
        ),
        BaseType::Struct(inst) => MoveValue::Struct(MoveStruct::new(
            val.into_struct()
                .into_iter()
                .zip(inst.fields.iter())
                .map(|(field_val, field_info)| {
                    convert_typed_value_to_move_value(&field_info.ty, field_val)
                })
                .collect(),
        )),
    }
}
<commit_msg>[stackless vm] print the bytecode after each pass in verbose mode<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::{bail, Result};
use structopt::StructOpt;

use bytecode::function_target_pipeline::{FunctionTargetPipeline, FunctionTargetsHolder};
use move_binary_format::errors::{Location, PartialVMError, VMResult};
use move_core_types::{
    account_address::AccountAddress,
    identifier::{IdentStr, Identifier},
    language_storage::{ModuleId, TypeTag},
    parser::{parse_transaction_argument, parse_type_tag},
    transaction_argument::TransactionArgument,
    value::{MoveStruct, MoveValue},
    vm_status::StatusCode,
};
use move_model::model::{FunctionEnv, GlobalEnv};

mod concrete;
mod shared;

use crate::concrete::{
    runtime::Runtime,
    ty::{BaseType, IntType, PrimitiveType},
    value::{BaseValue, GlobalState, TypedValue},
};

/// Options passed into the interpreter generator.
#[derive(StructOpt)]
pub struct InterpreterOptions {
    /// The function to be executed, specified in the format of `addr::module_name::function_name`
    #[structopt(long = "entry", parse(try_from_str = parse_entrypoint))]
    pub entrypoint: (ModuleId, Identifier),

    /// Possibly-empty list of signers for the execution
    #[structopt(long = "signers", parse(try_from_str = AccountAddress::from_hex_literal))]
    pub signers: Vec<AccountAddress>,
    /// Possibly-empty list of arguments passed to the transaction
    #[structopt(long = "args", parse(try_from_str = parse_transaction_argument))]
    pub args: Vec<TransactionArgument>,
    /// Possibly-empty list of type arguments passed to the transaction (e.g., `T` in
    /// `main<T>()`). Must match the type arguments kinds expected by `script_file`.
    #[structopt(long = "ty-args", parse(try_from_str = parse_type_tag))]
    pub ty_args: Vec<TypeTag>,

    /// Print verbose debug information
    #[structopt(short = "v", long = "verbose")]
    pub verbose: bool,
}

fn parse_entrypoint(input: &str) -> Result<(ModuleId, Identifier)> {
    let tokens: Vec<_> = input.split("::").collect();
    if tokens.len() != 3 {
        bail!("Invalid entrypoint: {}", input);
    }
    let module_id = ModuleId::new(
        AccountAddress::from_hex_literal(tokens[0])?,
        Identifier::new(tokens[1])?,
    );
    let func_name = Identifier::new(tokens[2])?;
    Ok((module_id, func_name))
}

#[derive(Debug, Eq, PartialEq)]
struct ExecutionResult {
    vm_result: VMResult<Vec<TypedValue>>,
    global_state: GlobalState,
}

//**************************************************************************************************
// Entry
//**************************************************************************************************
pub fn interpret_with_options(
    options: InterpreterOptions,
    env: &GlobalEnv,
    pipeline: FunctionTargetPipeline,
) -> VMResult<Vec<Vec<u8>>> {
    // consolidate arguments
    let args: Vec<_> = options
        .signers
        .into_iter()
        .map(MoveValue::Signer)
        .chain(options.args.into_iter().map(|arg| match arg {
            TransactionArgument::Bool(v) => MoveValue::Bool(v),
            TransactionArgument::U8(v) => MoveValue::U8(v),
            TransactionArgument::U64(v) => MoveValue::U64(v),
            TransactionArgument::U128(v) => MoveValue::U128(v),
            TransactionArgument::Address(v) => MoveValue::Address(v),
            TransactionArgument::U8Vector(v) => {
                MoveValue::Vector(v.into_iter().map(MoveValue::U8).collect())
            }
        }))
        .collect();

    // run the actual interpreter
    interpret(
        env,
        &options.entrypoint.0,
        &options.entrypoint.1,
        &options.ty_args,
        &args,
        pipeline,
        options.verbose,
    )
}

pub fn interpret(
    env: &GlobalEnv,
    module_id: &ModuleId,
    func_name: &IdentStr,
    ty_args: &[TypeTag],
    args: &[MoveValue],
    pipeline: FunctionTargetPipeline,
    verbose: bool,
) -> VMResult<Vec<Vec<u8>>> {
    // find the entrypoint
    let entrypoint_env = env
        .find_module_by_language_storage_id(module_id)
        .and_then(|module_env| module_env.find_function(env.symbol_pool().make(func_name.as_str())))
        .ok_or_else(|| {
            PartialVMError::new(StatusCode::LOOKUP_FAILED).finish(Location::Undefined)
        })?;
    if verbose {
        println!(
            "[compiled module]\n{:?}\n",
            entrypoint_env.module_env.get_verified_module()
        );
    }

    // collect and transform function targets
    let mut targets = FunctionTargetsHolder::default();
    for module_env in env.get_modules() {
        for func_env in module_env.get_functions() {
            targets.add_target(&func_env)
        }
    }
    if verbose {
        pipeline.run_with_hook(
            env,
            &mut targets,
            |holder| verbose_stepwise_processing(env, 0, "stackless", holder),
            |step, processor, holders| {
                verbose_stepwise_processing(env, step, &processor.name(), holders)
            },
        )
    } else {
        pipeline.run(env, &mut targets);
    }

    // execute and convert results
    let (vm_result, _) = interpret_internal(env, &targets, &entrypoint_env, ty_args, args, verbose);
    vm_result.map(|rets| {
        rets.into_iter()
            .map(|v| {
                let (ty, val, _) = v.decompose();
                let move_val = convert_typed_value_to_move_value(ty.get_base_type(), val);
                move_val.simple_serialize().unwrap()
            })
            .collect::<Vec<_>>()
    })
}

fn interpret_internal(
    env: &GlobalEnv,
    targets: &FunctionTargetsHolder,
    fun_env: &FunctionEnv,
    ty_args: &[TypeTag],
    args: &[MoveValue],
    verbose: bool,
) -> (VMResult<Vec<TypedValue>>, GlobalState) {
    // dump the bytecode if requested
    if verbose {
        let mut text = String::new();
        for module_env in env.get_modules() {
            for func_env in module_env.get_functions() {
                for (variant, target) in targets.get_targets(&func_env) {
                    target.register_annotation_formatters_for_test();
                    text += &format!("[variant {}]\n{}\n", variant, target);
                }
            }
        }
        println!("{}", text);
    }

    // invoke the runtime
    let vm = Runtime::new(env, targets);
    let global_state = GlobalState::default();
    vm.execute(fun_env, ty_args, args, global_state)
}

fn verbose_stepwise_processing(
    env: &GlobalEnv,
    step: usize,
    name: &str,
    targets: &FunctionTargetsHolder,
) {
    // short-circuit the execution if prior phases run into errors
    if env.has_errors() {
        return;
    }
    let mut text = String::new();
    for module_env in env.get_modules() {
        for func_env in module_env.get_functions() {
            for (_, target) in targets.get_targets(&func_env) {
                if !target.data.code.is_empty() {
                    target.register_annotation_formatters_for_test();
                    text += &format!("[{}-{}]\n{}\n", step, name, target);
                }
            }
        }
    }
    println!("{}", text);
}

fn convert_typed_value_to_move_value(ty: &BaseType, val: BaseValue) -> MoveValue {
    match ty {
        BaseType::Primitive(PrimitiveType::Bool) => MoveValue::Bool(val.into_bool()),
        BaseType::Primitive(PrimitiveType::Int(IntType::U8)) => MoveValue::U8(val.into_u8()),
        BaseType::Primitive(PrimitiveType::Int(IntType::U64)) => MoveValue::U64(val.into_u64()),
        BaseType::Primitive(PrimitiveType::Int(IntType::U128)) => MoveValue::U128(val.into_u128()),
        BaseType::Primitive(PrimitiveType::Int(IntType::Num)) => unreachable!(),
        BaseType::Primitive(PrimitiveType::Address) => MoveValue::Address(val.into_address()),
        BaseType::Primitive(PrimitiveType::Signer) => MoveValue::Signer(val.into_signer()),
        BaseType::Vector(elem) => MoveValue::Vector(
            val.into_vector()
                .into_iter()
                .map(|e| convert_typed_value_to_move_value(elem, e))
                .collect(),
        ),
        BaseType::Struct(inst) => MoveValue::Struct(MoveStruct::new(
            val.into_struct()
                .into_iter()
                .zip(inst.fields.iter())
                .map(|(field_val, field_info)| {
                    convert_typed_value_to_move_value(&field_info.ty, field_val)
                })
                .collect(),
        )),
    }
}
<|endoftext|>


<commit_before>//! It's a tree!

use std::ptr;
use std::ops::{Deref, DerefMut};
use std::fmt::Debug;

#[derive(Debug, PartialEq, Eq)]
struct Node<T> {
    // We need a mut pointer so we can modify the parent
    parent: *mut Node<T>,
    val: T,
    children: Vec<Node<T>>
}

impl<T> Node<T> {
    /// Create a new node with the existing value.
    /// For root-style constructors.
    pub fn new(val: T) -> Node<T> {
        Node {
            parent: ptr::null_mut(),
            val: val,
            children: Vec::new()
        }
    }

    /// Add a new child node to this node, using a value
    pub fn new_child(&mut self, val: T) -> &mut Node<T> {
        let self_mut = self as *mut Node<T>;
        self.children.push(Node {
            parent: self_mut,
            val: val,
            children: Vec::new()
        });
        let last_ix = self.children.len() -1;
        &mut self.children[last_ix]
    }

    /// Whether this node has a (currently-reachable) parent
    pub fn has_parent(&self) -> bool {
        self.parent.is_null()
    }

    /// Gets the parent of this node (if it exists)
    pub fn get_parent<'a>(&'a self) -> Option<&'a mut Node<T>> {
        if self.parent.is_null() {
            return None;
        }
        unsafe {
            return Some(&mut *self.parent);
        }
    }

    /// Borrow the children of this node.
    pub fn get_children<'a>(&'a self) -> &Vec<Node<T>> {
        &self.children
    }

    /// Mutably borrow the children of this mutable node
    pub fn get_mut_children(&mut self) -> &mut Vec<Node<T>> {
        &mut self.children
    }

    /// Remove a child at the given index
    pub fn remove_child_at(&mut self, index: usize) -> Node<T> {
        let mut child = self.children.remove(index);
        child.parent = ptr::null_mut();
        child
    }

    /// Whether this node is a parent of another node
    pub fn is_parent_of(&self, other: Node<T>) -> bool {
        self.parent == other.parent
    }
}

impl <T: PartialEq> Node<T> {

    /// Remove a node from its parent.
    /// This method will mutate the parent if it exists.
    pub fn remove_from_parent(&self) {
        if let Some(ref mut parent) = self.get_parent() {
            let children = parent.get_mut_children();
            if let Some(index) = children.iter().position(|c| c == self) {
                children.remove(index);
            }
        }
    }

    /// Removes a child from self
    pub fn remove_child(&mut self, other: &Node<T>) -> Option<Node<T>> {
        if let Some(index) = self.children.iter().position(|c| c == other) {
            Some(self.children.remove(index))
        }
        else {
            None
        }
    }

    pub fn move_to(mut self, new_parent: &mut Node<T>) {
        self.remove_from_parent();
        self.parent = new_parent as *mut Node<T>;
        new_parent.children.push(self);
    }
}

impl<T> Drop for Node<T> {
    fn drop(&mut self) {
        println!("Dropping a node.");
        self.parent = ptr::null_mut();
        let children: &mut Vec<Node<T>> = &mut self.children;
        for mut child in children {
            println!("> Unlinking a child");
            child.parent = ptr::null_mut();
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Node;
    use log::LogLevelFilter;
    use env_logger::LogBuilder;

    /// Nodes can have children added to them
    #[test]
    fn test_add_child() {
        let mut root = Node::new(0);
        root.new_child(1);
        root.new_child(2); // This is okay
        {
            let mut third_child = root.new_child(3);
            //root.new_child(4); // Have to wait for 3rd child to drop
        }
        root.new_child(4); // Now this works yay standard borrowing
        assert_eq!(root.children.len(), 4);
        println!("Done with the test now.");
    }

    /// These operations will for example operate on the parent
    /// under an if let. `remove_from_parent` will not panic if the node
    /// already is parentless, for example.
    #[test]
    fn optional_operations() {

    }
}
<commit_msg>Update unsafetree.rs<commit_after>//! It's a tree!

use std::ptr;
use std::ops::{Deref, DerefMut};
use std::fmt::Debug;

#[derive(Debug, PartialEq, Eq)]
struct Node<T> {
    // We need a mut pointer so we can modify the parent
    parent: *mut Node<T>,
    val: T,
    children: Vec<Node<T>>
}

impl<T> Node<T> {
    /// Create a new node with the existing value.
    /// For root-style constructors.
    pub fn new(val: T) -> Node<T> {
        Node {
            parent: ptr::null_mut(),
            val: val,
            children: Vec::new()
        }
    }

    /// Add a new child node to this node, using a value
    pub fn new_child(&mut self, val: T) -> &mut Node<T> {
        let self_mut = self as *mut Node<T>;
        self.children.push(Node {
            parent: self_mut,
            val: val,
            children: Vec::new()
        });
        let last_ix = self.children.len() -1;
        &mut self.children[last_ix]
    }

    /// Whether this node has a (currently-reachable) parent
    pub fn has_parent(&self) -> bool {
        self.parent.is_null()
    }

    /// Gets the parent of this node (if it exists)
    pub fn get_parent(&self) -> Option<&mut Node<T>> {
        if self.parent.is_null() {
            return None;
        }
        unsafe {
            return Some(&mut *self.parent);
        }
    }

    /// Borrow the children of this node.
    pub fn get_children<'a>(&'a self) -> &Vec<Node<T>> {
        &self.children
    }

    /// Mutably borrow the children of this mutable node
    pub fn get_mut_children(&mut self) -> &mut Vec<Node<T>> {
        &mut self.children
    }

    /// Remove a child at the given index
    pub fn remove_child_at(&mut self, index: usize) -> Node<T> {
        let mut child = self.children.remove(index);
        child.parent = ptr::null_mut();
        child
    }

    /// Whether this node is a parent of another node
    pub fn is_parent_of(&self, other: Node<T>) -> bool {
        self.parent == other.parent
    }
}

impl <T: PartialEq> Node<T> {

    /// Remove a node from its parent.
    /// This method will mutate the parent if it exists.
    pub fn remove_from_parent(&self) {
        if let Some(ref mut parent) = self.get_parent() {
            let children = parent.get_mut_children();
            if let Some(index) = children.iter().position(|c| c == self) {
                children.remove(index);
            }
        }
    }

    /// Removes a child from self
    pub fn remove_child(&mut self, other: &Node<T>) -> Option<Node<T>> {
        if let Some(index) = self.children.iter().position(|c| c == other) {
            Some(self.children.remove(index))
        }
        else {
            None
        }
    }

    pub fn move_to(mut self, new_parent: &mut Node<T>) {
        self.remove_from_parent();
        self.parent = new_parent as *mut Node<T>;
        new_parent.children.push(self);
    }
}

impl<T> Drop for Node<T> {
    fn drop(&mut self) {
        println!("Dropping a node.");
        let children: &mut Vec<Node<T>> = &mut self.children;
        for mut child in children {
            println!("> Unlinking a child");
            child.parent = ptr::null_mut();
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Node;
    use log::LogLevelFilter;
    use env_logger::LogBuilder;

    /// Nodes can have children added to them
    #[test]
    fn test_add_child() {
        let mut root = Node::new(0);
        root.new_child(1);
        root.new_child(2); // This is okay
        {
            let mut third_child = root.new_child(3);
            //root.new_child(4); // Have to wait for 3rd child to drop
        }
        root.new_child(4); // Now this works yay standard borrowing
        assert_eq!(root.children.len(), 4);
        println!("Done with the test now.");
    }

    /// These operations will for example operate on the parent
    /// under an if let. `remove_from_parent` will not panic if the node
    /// already is parentless, for example.
    #[test]
    fn optional_operations() {

    }
}
<|endoftext|>