<commit_before>#[macro_export]
macro_rules! into_property_source {
    ($type:ty $(: $( $ex_type:ty ),*)* ) => {
        impl IntoPropertySource<$type> for $type {
            fn into_source(self) -> PropertySource<$type> {
                PropertySource::Value(self)
            }
        }

        impl IntoPropertySource<$type> for Entity {
            fn into_source(self) -> PropertySource<$type> {
                PropertySource::Source(self)
            }
        }

        impl IntoPropertySource<$type> for (String, Entity) {
            fn into_source(self) -> PropertySource<$type> {
                PropertySource::KeySource(self.0, self.1)
            }
        }

        impl IntoPropertySource<$type> for (&str, Entity) {
            fn into_source(self) -> PropertySource<$type> {
                PropertySource::KeySource(self.0.to_string(), self.1)
            }
        }

         $(
            $(
                impl IntoPropertySource<$type> for $ex_type {
                    fn into_source(self) -> PropertySource<$type> {
                        PropertySource::Value(self.into())
                    }
                }
            )*
        )*
    };
}

/// Used to define a widget, with properties and event handlers.
#[macro_export]
macro_rules! widget {
    ( $(#[$widget_doc:meta])* $widget:ident $(<$state:ident>)* $(: $( $handler:ident ),*)*
            $( { $($(#[$prop_doc:meta])* $property:ident: $property_type:tt ),*
                $( attached_properties: { $($(#[$att_prop_doc:meta])* $att_property:ident: $att_property_type:tt ),* } )*
             } )* ) => {
        $(#[$widget_doc])*
        #[derive(Default, WidgetCtx)]
        pub struct $widget {
            attached_properties: HashMap<String, ComponentBox>,
            shared_attached_properties: HashMap<(String, String), SharedComponentBox>,
            event_handlers: Vec<Rc<dyn EventHandler>>,
            #[property(Rectangle)]
            bounds: Rectangle,
            #[property(Point)]
            position: Point,
            #[property(Constraint)]
            constraint: Constraint,
            min_width: Option<f64>,
            min_height: Option<f64>,
            max_width: Option<f64>,
            max_height: Option<f64>,
            width: Option<f64>,
            height: Option<f64>,
            name: Option<String>,
            element: Option<String>,
            id: Option<String>,
            classes: HashSet<String>,
            #[property(Alignment)]
            h_align: Alignment,
            #[property(Alignment)]
            v_align: Alignment,
            #[property(Thickness)]
            margin: Thickness,
            #[property(bool)]
            enabled: bool,
            #[property(bool)]
            clip: bool,
            #[property(f32)]
            opacity: f32,
            #[property(Visibility)]
            visibility: Visibility,
            _empty: Option<RefCell<i32>>,
             $(
                $(
                    #[property($property_type)]
                    $property: Option<PropertySource<$property_type>>,
                )*
             )*
            children: Vec<Entity>,
            $(
                state: Box<$state>
            )*
        }

        impl $widget {
            // internal helper
            fn set_property<P: Component + Debug>(mut self, key: &str, property: impl IntoPropertySource<P>) -> Self {
                match property.into_source() {
                    PropertySource::Value(value) => {
                        self.attached_properties.insert(key.to_string(), ComponentBox::new(value));
                    },
                    PropertySource::Source(source) => {
                        self.shared_attached_properties.insert((key.to_string(), key.to_string()), SharedComponentBox::new(TypeId::of::<P>(), source));
                    }
                    PropertySource::KeySource(source_key, source) => {
                        self.shared_attached_properties.insert((key.to_string(), source_key), SharedComponentBox::new(TypeId::of::<P>(), source));
                    }
                }
                self
            }

            /// Sets the id selector.
            pub fn id(mut self, id: impl Into<String>) -> Self {
                if !self.id.is_none() {
                    return self;
                }
                self.id = Some(id.into());
                self
            }

            /// Sets the element selector.
            pub fn element(mut self, element: impl Into<String>) -> Self {
                if !self.element.is_none() {
                    return self;
                }

                self.element = Some(element.into());
                self
            }

            /// Inserts class selector.
            pub fn class(mut self, class: impl Into<String>) -> Self {
                self.classes.insert(class.into());
                self
            }

            /// Sets or shares the position of the widget. (Be careful the position could be adjusted by layouts).
            pub fn position(self, position: impl IntoPropertySource<Point>) -> Self {
                self.set_property("position", position)
            }

            /// Sets or shares the constraint property.
            pub fn constraint(self, constraint: impl IntoPropertySource<Constraint>) -> Self {
                self.set_property("constraint", constraint)
            }

            /// Sets or shares the vertical alignment property.
            #[inline(always)]
            pub fn v_align(self, v_align: impl IntoPropertySource<Alignment>) -> Self {
                self.set_property("v_align", v_align)
            }

             /// Sets or shares the horizontal alignment property.
             #[inline(always)]
             pub fn h_align(self, h_align: impl IntoPropertySource<Alignment>) -> Self {
                 self.set_property("h_align", h_align)
             }

            /// Sets or shares the vertical alignment property.
            #[inline(always)]
            #[deprecated = "Use v_align instead"]
            pub fn vertical_alignment(self, vertical_alignment: impl IntoPropertySource<Alignment>) -> Self {
                self.v_align(vertical_alignment)
            }

            /// Sets or shares the horizontal alignment property.
            #[inline(always)]
            #[deprecated = "Use h_align instead"]
            pub fn horizontal_alignment(self, horizontal_alignment: impl IntoPropertySource<Alignment>) -> Self {
                self.h_align(horizontal_alignment)
            }

            /// Sets or shares the visibility property.
            pub fn visibility(self, visibility: impl IntoPropertySource<Visibility>) -> Self {
                self.set_property("visibility", visibility)
            }

            /// Sets or shares the margin property.
            pub fn margin(self, margin: impl IntoPropertySource<Thickness>) -> Self {
                self.set_property("margin", margin)
            }

            /// Sets or shares the enabled property.
            pub fn enabled(self, enabled: impl IntoPropertySource<bool>) -> Self {
                self.set_property("enabled", enabled)
            }

            /// Sets or shares the clip property.
            pub fn clip(self, clip: impl IntoPropertySource<bool>) -> Self {
                self.set_property("clip", clip)
            }

            // Sets or shares the opacity property.
            pub fn opacity(self, opacity: impl IntoPropertySource<f32>) -> Self {
                self.set_property("opacity", opacity)
            }

            /// Inserts a new width.
            pub fn width(mut self, width: f64) -> Self {
                if !self.width.is_none() {
                    return self;
                }
                self.width = Some(width);
                self
            }

            /// Inserts a new height.
            pub fn height(mut self, height: f64) -> Self {
                if !self.height.is_none() {
                    return self;
                }
                self.height = Some(height);
                self
            }

            /// Inserts a new size.
            pub fn size(mut self, width: f64, height: f64) -> Self {
                if self.width.is_none() {
                    self.width = Some(width);
                }
                if self.height.is_none() {
                    self.height = Some(height);
                }
                self
            }

            /// Inserts a new min_width.
            pub fn min_width(mut self, min_width: f64) -> Self {
                if !self.min_width.is_none() {
                    return self;
                }
                self.min_width = Some(min_width);
                self
            }

            /// Inserts a new min_height.
            pub fn min_height(mut self, min_height: f64) -> Self {
                if !self.min_height.is_none() {
                    return self;
                }
                self.min_height = Some(min_height);
                self
            }

            /// Inserts a new min_size.
            pub fn min_size(mut self, min_width: f64, min_height: f64) -> Self {
                if self.min_width.is_none() {
                    self.min_width = Some(min_width);
                }
                if self.min_height.is_none() {
                    self.min_height = Some(min_height);
                }
                self
            }

            /// Inserts a new max_width.
            pub fn max_width(mut self, max_width: f64) -> Self {
                if !self.max_width.is_none() {
                    return self;
                }
                self.max_width = Some(max_width);
                self
            }

            /// Inserts a new max_height.
            pub fn max_height(mut self, max_height: f64) -> Self {
                if !self.max_height.is_none() {
                    return self;
                }
                self.max_height = Some(max_height);
                self
            }

            /// Inserts a new min_size.
            pub fn max_size(mut self, max_width: f64, max_height: f64) -> Self {
                if self.max_width.is_none() {
                    self.max_width = Some(max_width);
                }
                if self.max_height.is_none() {
                    self.max_height = Some(max_height);
                }
                self
            }

            /// Sets the debug name of the widget.
            pub fn name<P: Into<String>>(mut self, name: P) -> Self {
                self.name = Some(name.into());
                self
            }

            $(
                /// Gets a reference of the state.
                fn state(&self) -> &Box<$state> {
                    &self.state
                }

                /// Gets a mutable reference of the state.
                fn state_mut(&mut self) -> &mut Box<$state> {
                    &mut self.state
                }
            )*

            $(
                $(
                    $(#[$prop_doc])*
                    pub fn $property<P: IntoPropertySource<$property_type>>(mut self, $property: P) -> Self {
                        if !self.$property.is_none() {
                            return self;
                        }

                        self.$property = Some($property.into_source());
                        self
                    }
                )*
            )*

            $(
                $(
                    $(
                        $(#[$att_prop_doc])*
                        pub fn $att_property(property: impl IntoPropertySource<$att_property_type>) -> AttachedProperty<$att_property_type> {
                            AttachedProperty::new(stringify!($att_property), property)
                        }
                    )*
                )*
            )*
        }

        $(
            $(
                impl $handler for $widget {}
            )*
        )*

        impl Widget for $widget {
            /// Creates a new widget.
            #[inline]
            fn new() -> Self {
                $widget {
                    event_handlers: vec![],
                    enabled: true,
                    opacity: 1.,
                    clip: false,
                    $(
                        $(
                            $property: None,
                        )*
                    )*
                    children: vec![],
                    ..Default::default()
                }
            }

            fn attach<P: Component + Debug>(mut self, property: AttachedProperty<P>) -> Self {
                match property.property_source {
                    PropertySource::Value(value) => {
                        self.attached_properties.insert(property.key, ComponentBox::new(value));
                    }
                    PropertySource::Source(source) => {
                        self.shared_attached_properties.insert((property.key.clone(), property.key), SharedComponentBox::new(TypeId::of::<P>(), source));
                    }
                    PropertySource::KeySource(source_key, source) => {
                        self.shared_attached_properties.insert((property.key, source_key), SharedComponentBox::new(TypeId::of::<P>(), source));
                    }
                }
                self
            }

            fn insert_handler(mut self, handler: impl Into<Rc<dyn EventHandler>>) -> Self {
                self.event_handlers.push(handler.into());
                self
            }

            fn child(mut self, child: Entity) -> Self {
                self.children.push(child);
                self
            }

            fn build(self, ctx: &mut BuildContext) -> Entity {
                let entity = ctx.create_entity();

                let this = self.template(entity, ctx);

                ctx.register_render_object(entity, this.render_object());
                ctx.register_layout(entity, this.layout());

                $(
                    // workaround
                    let _ = TypeId::of::<$state>();
                    ctx.register_state(entity, this.state);
                )*

                // register default set of properties
                ctx.register_property("bounds", entity, this.bounds);
                ctx.register_property("position", entity, this.position);
                ctx.register_property("v_align", entity, this.v_align);
                ctx.register_property("h_align", entity, this.h_align);
                ctx.register_property("visibility", entity, this.visibility);
                ctx.register_property("margin", entity, this.margin);
                ctx.register_property("enabled", entity, this.enabled);
                ctx.register_property("clip", entity, this.clip);
                ctx.register_property("opacity", entity, this.opacity);
                ctx.register_property("type_id", entity, TypeId::of::<$widget>());
                ctx.register_property("type_name", entity, std::any::type_name::<$widget>().to_string());

                if this.element.is_some() || this.id.is_some() || this.classes.len() > 0 {
                    let mut selector = Selector::new();
                    //selector.set_dirty(true);
                    if let Some(element) = this.element {
                        selector = selector.with(element);
                    }
                    if let Some(id) = this.id {
                        selector = selector.id(id);
                    }
                    let mut classes = this.classes;
                    for class in classes.drain() {
                        selector = selector.class(class);
                    }
                    ctx.register_property("selector", entity, selector);
                }

                let mut constraint = Constraint::default();

                if let Some(width) = this.width {
                    constraint.set_width(width);
                }
                if let Some(height) = this.height {
                    constraint.set_height(height);
                }
                if let Some(min_width) = this.min_width {
                    constraint.set_min_width(min_width);
                }
                if let Some(min_height) = this.min_height {
                    constraint.set_min_height(min_height);
                }
                if let Some(max_width) = this.max_width {
                    constraint.set_max_width(max_width);
                }
                if let Some(max_height) = this.max_height {
                    constraint.set_max_height(max_height);
                }
                ctx.register_property("constraint", entity, constraint);

                // register attached properties
                for (key, property) in this.attached_properties {
                    ctx.register_property_box(key.as_str(), entity, property);
                }

                for (key, property) in this.shared_attached_properties {
                    ctx.register_property_shared_box_by_source_key(key.0.as_str(), key.1.as_str(), entity, property);
                }

                // register properties
                $(
                    $(
                        if let Some($property) = this.$property {
                            match $property {
                                PropertySource::Value(value) => {
                                    ctx.register_property(stringify!($property), entity, value);
                                }
                                PropertySource::Source(source) => {
                                    ctx.register_shared_property::<$property_type>(stringify!($property), entity, source);
                                }
                                PropertySource::KeySource(source_key, source) => {
                                    ctx.register_shared_property_by_source_key::<$property_type>(stringify!($property), source_key.as_str(), entity, source);
                                }
                            }
                        }
                        else {
                            ctx.register_property(stringify!($property), entity, $property_type::default());
                        }
                    )*
                )*

                ctx.update_theme_by_state(entity);

                // register event handlers
                for handler in this.event_handlers {
                    ctx.register_handler(entity, handler);
                }

                // register name
                if let Some(name) = this.name {
                    ctx.register_property("name", entity, name);
                }

                for child in this.children {
                    ctx.append_child(entity, child);
                }

                entity
            }
        }
    };
}
<commit_msg>Fix warning in widget macro.<commit_after>#[macro_export]
macro_rules! into_property_source {
    ($type:ty $(: $( $ex_type:ty ),*)* ) => {
        impl IntoPropertySource<$type> for $type {
            fn into_source(self) -> PropertySource<$type> {
                PropertySource::Value(self)
            }
        }

        impl IntoPropertySource<$type> for Entity {
            fn into_source(self) -> PropertySource<$type> {
                PropertySource::Source(self)
            }
        }

        impl IntoPropertySource<$type> for (String, Entity) {
            fn into_source(self) -> PropertySource<$type> {
                PropertySource::KeySource(self.0, self.1)
            }
        }

        impl IntoPropertySource<$type> for (&str, Entity) {
            fn into_source(self) -> PropertySource<$type> {
                PropertySource::KeySource(self.0.to_string(), self.1)
            }
        }

         $(
            $(
                impl IntoPropertySource<$type> for $ex_type {
                    fn into_source(self) -> PropertySource<$type> {
                        PropertySource::Value(self.into())
                    }
                }
            )*
        )*
    };
}

/// Used to define a widget, with properties and event handlers.
#[macro_export]
macro_rules! widget {
    ( $(#[$widget_doc:meta])* $widget:ident $(<$state:ident>)* $(: $( $handler:ident ),*)*
            $( { $($(#[$prop_doc:meta])* $property:ident: $property_type:tt ),*
                $( attached_properties: { $($(#[$att_prop_doc:meta])* $att_property:ident: $att_property_type:tt ),* } )*
             } )* ) => {
        $(#[$widget_doc])*
        #[derive(Default, WidgetCtx)]
        #[allow(dead_code)]
        pub struct $widget {
            attached_properties: HashMap<String, ComponentBox>,
            shared_attached_properties: HashMap<(String, String), SharedComponentBox>,
            event_handlers: Vec<Rc<dyn EventHandler>>,
            #[property(Rectangle)]
            bounds: Rectangle,
            #[property(Point)]
            position: Point,
            #[property(Constraint)]
            constraint: Constraint,
            min_width: Option<f64>,
            min_height: Option<f64>,
            max_width: Option<f64>,
            max_height: Option<f64>,
            width: Option<f64>,
            height: Option<f64>,
            name: Option<String>,
            element: Option<String>,
            id: Option<String>,
            classes: HashSet<String>,
            #[property(Alignment)]
            h_align: Alignment,
            #[property(Alignment)]
            v_align: Alignment,
            #[property(Thickness)]
            margin: Thickness,
            #[property(bool)]
            enabled: bool,
            #[property(bool)]
            clip: bool,
            #[property(f32)]
            opacity: f32,
            #[property(Visibility)]
            visibility: Visibility,
            _empty: Option<RefCell<i32>>,
             $(
                $(
                    #[property($property_type)]
                    $property: Option<PropertySource<$property_type>>,
                )*
             )*
            children: Vec<Entity>,
            $(
                state: Box<$state>
            )*
        }

        impl $widget {
            // internal helper
            fn set_property<P: Component + Debug>(mut self, key: &str, property: impl IntoPropertySource<P>) -> Self {
                match property.into_source() {
                    PropertySource::Value(value) => {
                        self.attached_properties.insert(key.to_string(), ComponentBox::new(value));
                    },
                    PropertySource::Source(source) => {
                        self.shared_attached_properties.insert((key.to_string(), key.to_string()), SharedComponentBox::new(TypeId::of::<P>(), source));
                    }
                    PropertySource::KeySource(source_key, source) => {
                        self.shared_attached_properties.insert((key.to_string(), source_key), SharedComponentBox::new(TypeId::of::<P>(), source));
                    }
                }
                self
            }

            /// Sets the id selector.
            pub fn id(mut self, id: impl Into<String>) -> Self {
                if !self.id.is_none() {
                    return self;
                }
                self.id = Some(id.into());
                self
            }

            /// Sets the element selector.
            pub fn element(mut self, element: impl Into<String>) -> Self {
                if !self.element.is_none() {
                    return self;
                }

                self.element = Some(element.into());
                self
            }

            /// Inserts class selector.
            pub fn class(mut self, class: impl Into<String>) -> Self {
                self.classes.insert(class.into());
                self
            }

            /// Sets or shares the position of the widget. (Be careful the position could be adjusted by layouts).
            pub fn position(self, position: impl IntoPropertySource<Point>) -> Self {
                self.set_property("position", position)
            }

            /// Sets or shares the constraint property.
            pub fn constraint(self, constraint: impl IntoPropertySource<Constraint>) -> Self {
                self.set_property("constraint", constraint)
            }

            /// Sets or shares the vertical alignment property.
            #[inline(always)]
            pub fn v_align(self, v_align: impl IntoPropertySource<Alignment>) -> Self {
                self.set_property("v_align", v_align)
            }

             /// Sets or shares the horizontal alignment property.
             #[inline(always)]
             pub fn h_align(self, h_align: impl IntoPropertySource<Alignment>) -> Self {
                 self.set_property("h_align", h_align)
             }

            /// Sets or shares the vertical alignment property.
            #[inline(always)]
            #[deprecated = "Use v_align instead"]
            pub fn vertical_alignment(self, vertical_alignment: impl IntoPropertySource<Alignment>) -> Self {
                self.v_align(vertical_alignment)
            }

            /// Sets or shares the horizontal alignment property.
            #[inline(always)]
            #[deprecated = "Use h_align instead"]
            pub fn horizontal_alignment(self, horizontal_alignment: impl IntoPropertySource<Alignment>) -> Self {
                self.h_align(horizontal_alignment)
            }

            /// Sets or shares the visibility property.
            pub fn visibility(self, visibility: impl IntoPropertySource<Visibility>) -> Self {
                self.set_property("visibility", visibility)
            }

            /// Sets or shares the margin property.
            pub fn margin(self, margin: impl IntoPropertySource<Thickness>) -> Self {
                self.set_property("margin", margin)
            }

            /// Sets or shares the enabled property.
            pub fn enabled(self, enabled: impl IntoPropertySource<bool>) -> Self {
                self.set_property("enabled", enabled)
            }

            /// Sets or shares the clip property.
            pub fn clip(self, clip: impl IntoPropertySource<bool>) -> Self {
                self.set_property("clip", clip)
            }

            // Sets or shares the opacity property.
            pub fn opacity(self, opacity: impl IntoPropertySource<f32>) -> Self {
                self.set_property("opacity", opacity)
            }

            /// Inserts a new width.
            pub fn width(mut self, width: f64) -> Self {
                if !self.width.is_none() {
                    return self;
                }
                self.width = Some(width);
                self
            }

            /// Inserts a new height.
            pub fn height(mut self, height: f64) -> Self {
                if !self.height.is_none() {
                    return self;
                }
                self.height = Some(height);
                self
            }

            /// Inserts a new size.
            pub fn size(mut self, width: f64, height: f64) -> Self {
                if self.width.is_none() {
                    self.width = Some(width);
                }
                if self.height.is_none() {
                    self.height = Some(height);
                }
                self
            }

            /// Inserts a new min_width.
            pub fn min_width(mut self, min_width: f64) -> Self {
                if !self.min_width.is_none() {
                    return self;
                }
                self.min_width = Some(min_width);
                self
            }

            /// Inserts a new min_height.
            pub fn min_height(mut self, min_height: f64) -> Self {
                if !self.min_height.is_none() {
                    return self;
                }
                self.min_height = Some(min_height);
                self
            }

            /// Inserts a new min_size.
            pub fn min_size(mut self, min_width: f64, min_height: f64) -> Self {
                if self.min_width.is_none() {
                    self.min_width = Some(min_width);
                }
                if self.min_height.is_none() {
                    self.min_height = Some(min_height);
                }
                self
            }

            /// Inserts a new max_width.
            pub fn max_width(mut self, max_width: f64) -> Self {
                if !self.max_width.is_none() {
                    return self;
                }
                self.max_width = Some(max_width);
                self
            }

            /// Inserts a new max_height.
            pub fn max_height(mut self, max_height: f64) -> Self {
                if !self.max_height.is_none() {
                    return self;
                }
                self.max_height = Some(max_height);
                self
            }

            /// Inserts a new min_size.
            pub fn max_size(mut self, max_width: f64, max_height: f64) -> Self {
                if self.max_width.is_none() {
                    self.max_width = Some(max_width);
                }
                if self.max_height.is_none() {
                    self.max_height = Some(max_height);
                }
                self
            }

            /// Sets the debug name of the widget.
            pub fn name<P: Into<String>>(mut self, name: P) -> Self {
                self.name = Some(name.into());
                self
            }

            $(
                /// Gets a reference of the state.
                fn state(&self) -> &Box<$state> {
                    &self.state
                }

                /// Gets a mutable reference of the state.
                fn state_mut(&mut self) -> &mut Box<$state> {
                    &mut self.state
                }
            )*

            $(
                $(
                    $(#[$prop_doc])*
                    pub fn $property<P: IntoPropertySource<$property_type>>(mut self, $property: P) -> Self {
                        if !self.$property.is_none() {
                            return self;
                        }

                        self.$property = Some($property.into_source());
                        self
                    }
                )*
            )*

            $(
                $(
                    $(
                        $(#[$att_prop_doc])*
                        pub fn $att_property(property: impl IntoPropertySource<$att_property_type>) -> AttachedProperty<$att_property_type> {
                            AttachedProperty::new(stringify!($att_property), property)
                        }
                    )*
                )*
            )*
        }

        $(
            $(
                impl $handler for $widget {}
            )*
        )*

        impl Widget for $widget {
            /// Creates a new widget.
            #[inline]
            fn new() -> Self {
                $widget {
                    event_handlers: vec![],
                    enabled: true,
                    opacity: 1.,
                    clip: false,
                    $(
                        $(
                            $property: None,
                        )*
                    )*
                    children: vec![],
                    ..Default::default()
                }
            }

            fn attach<P: Component + Debug>(mut self, property: AttachedProperty<P>) -> Self {
                match property.property_source {
                    PropertySource::Value(value) => {
                        self.attached_properties.insert(property.key, ComponentBox::new(value));
                    }
                    PropertySource::Source(source) => {
                        self.shared_attached_properties.insert((property.key.clone(), property.key), SharedComponentBox::new(TypeId::of::<P>(), source));
                    }
                    PropertySource::KeySource(source_key, source) => {
                        self.shared_attached_properties.insert((property.key, source_key), SharedComponentBox::new(TypeId::of::<P>(), source));
                    }
                }
                self
            }

            fn insert_handler(mut self, handler: impl Into<Rc<dyn EventHandler>>) -> Self {
                self.event_handlers.push(handler.into());
                self
            }

            fn child(mut self, child: Entity) -> Self {
                self.children.push(child);
                self
            }

            fn build(self, ctx: &mut BuildContext) -> Entity {
                let entity = ctx.create_entity();

                let this = self.template(entity, ctx);

                ctx.register_render_object(entity, this.render_object());
                ctx.register_layout(entity, this.layout());

                $(
                    // workaround
                    let _ = TypeId::of::<$state>();
                    ctx.register_state(entity, this.state);
                )*

                // register default set of properties
                ctx.register_property("bounds", entity, this.bounds);
                ctx.register_property("position", entity, this.position);
                ctx.register_property("v_align", entity, this.v_align);
                ctx.register_property("h_align", entity, this.h_align);
                ctx.register_property("visibility", entity, this.visibility);
                ctx.register_property("margin", entity, this.margin);
                ctx.register_property("enabled", entity, this.enabled);
                ctx.register_property("clip", entity, this.clip);
                ctx.register_property("opacity", entity, this.opacity);
                ctx.register_property("type_id", entity, TypeId::of::<$widget>());
                ctx.register_property("type_name", entity, std::any::type_name::<$widget>().to_string());

                if this.element.is_some() || this.id.is_some() || this.classes.len() > 0 {
                    let mut selector = Selector::new();
                    //selector.set_dirty(true);
                    if let Some(element) = this.element {
                        selector = selector.with(element);
                    }
                    if let Some(id) = this.id {
                        selector = selector.id(id);
                    }
                    let mut classes = this.classes;
                    for class in classes.drain() {
                        selector = selector.class(class);
                    }
                    ctx.register_property("selector", entity, selector);
                }

                let mut constraint = Constraint::default();

                if let Some(width) = this.width {
                    constraint.set_width(width);
                }
                if let Some(height) = this.height {
                    constraint.set_height(height);
                }
                if let Some(min_width) = this.min_width {
                    constraint.set_min_width(min_width);
                }
                if let Some(min_height) = this.min_height {
                    constraint.set_min_height(min_height);
                }
                if let Some(max_width) = this.max_width {
                    constraint.set_max_width(max_width);
                }
                if let Some(max_height) = this.max_height {
                    constraint.set_max_height(max_height);
                }
                ctx.register_property("constraint", entity, constraint);

                // register attached properties
                for (key, property) in this.attached_properties {
                    ctx.register_property_box(key.as_str(), entity, property);
                }

                for (key, property) in this.shared_attached_properties {
                    ctx.register_property_shared_box_by_source_key(key.0.as_str(), key.1.as_str(), entity, property);
                }

                // register properties
                $(
                    $(
                        if let Some($property) = this.$property {
                            match $property {
                                PropertySource::Value(value) => {
                                    ctx.register_property(stringify!($property), entity, value);
                                }
                                PropertySource::Source(source) => {
                                    ctx.register_shared_property::<$property_type>(stringify!($property), entity, source);
                                }
                                PropertySource::KeySource(source_key, source) => {
                                    ctx.register_shared_property_by_source_key::<$property_type>(stringify!($property), source_key.as_str(), entity, source);
                                }
                            }
                        }
                        else {
                            ctx.register_property(stringify!($property), entity, $property_type::default());
                        }
                    )*
                )*

                ctx.update_theme_by_state(entity);

                // register event handlers
                for handler in this.event_handlers {
                    ctx.register_handler(entity, handler);
                }

                // register name
                if let Some(name) = this.name {
                    ctx.register_property("name", entity, name);
                }

                for child in this.children {
                    ctx.append_child(entity, child);
                }

                entity
            }
        }
    };
}
<|endoftext|>


<commit_before>//! A set of builders used to make using methods on certain structs simpler to
//! use.
//!
//! These are used when not all parameters are required, all parameters are
//! optional, and/or sane default values for required parameters can be applied
//! by a builder.

mod create_embed;
mod create_invite;
mod create_message;
mod edit_channel;
mod edit_guild;
mod edit_member;
mod edit_profile;
mod edit_role;
mod execute_webhook;
mod get_messages;

pub use self::create_embed::{
    CreateEmbed,
    CreateEmbedAuthor,
    CreateEmbedField,
    CreateEmbedImage,
    CreateEmbedThumbnail,
    CreateEmbedVideo,
};
pub use self::create_invite::CreateInvite;
pub use self::create_message::CreateMessage;
pub use self::edit_channel::EditChannel;
pub use self::edit_guild::EditGuild;
pub use self::edit_member::EditMember;
pub use self::edit_profile::EditProfile;
pub use self::edit_role::EditRole;
pub use self::execute_webhook::ExecuteWebhook;
pub use self::get_messages::GetMessages;
<commit_msg>Re-export CreateEmbedFooter<commit_after>//! A set of builders used to make using methods on certain structs simpler to
//! use.
//!
//! These are used when not all parameters are required, all parameters are
//! optional, and/or sane default values for required parameters can be applied
//! by a builder.

mod create_embed;
mod create_invite;
mod create_message;
mod edit_channel;
mod edit_guild;
mod edit_member;
mod edit_profile;
mod edit_role;
mod execute_webhook;
mod get_messages;

pub use self::create_embed::{
    CreateEmbed,
    CreateEmbedAuthor,
    CreateEmbedFooter,
    CreateEmbedField,
    CreateEmbedImage,
    CreateEmbedThumbnail,
    CreateEmbedVideo,
};
pub use self::create_invite::CreateInvite;
pub use self::create_message::CreateMessage;
pub use self::edit_channel::EditChannel;
pub use self::edit_guild::EditGuild;
pub use self::edit_member::EditMember;
pub use self::edit_profile::EditProfile;
pub use self::edit_role::EditRole;
pub use self::execute_webhook::ExecuteWebhook;
pub use self::get_messages::GetMessages;
<|endoftext|>


<commit_before>// Copyright 2018 Chao Lin & William Sergeant (Sorbonne University)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![macro_use]
use middle::analysis::ast::*;
use std::collections::HashSet;

enum SetInclusion {
    Empty,
    Conjunction(Vec<SetInclusion>),
    Disjunction(Vec<SetInclusion>)
}

pub struct UnreachableRule<'a: 'c, 'b: 'a, 'c>
{
  grammar: &'c AGrammar<'a, 'b>,
  in_choice: bool,
  hash_set_vector: Vec<HashSet<String>>,
  current_set: HashSet<String>
}

impl <'a, 'b, 'c> UnreachableRule<'a, 'b, 'c>
{
  pub fn analyse(grammar: AGrammar<'a, 'b>) -> Partial<AGrammar<'a, 'b>> {
    UnreachableRule::check_unreachable_rule(&grammar);
    Partial::Value(grammar)
  }

  fn check_unreachable_rule(grammar: &'c AGrammar<'a, 'b>){
    let mut analyser = UnreachableRule{
      grammar: grammar,
      in_choice: false,
      hash_set_vector: vec![],
      current_set: HashSet::new()
    };

    for rule in &grammar.rules {
      analyser.visit_expr(rule.expr_idx)
    }
  }
}

impl<'a, 'b, 'c> ExprByIndex for UnreachableRule<'a, 'b, 'c>
{
  fn expr_by_index(&self, index: usize) -> Expression {
    self.grammar.expr_by_index(index).clone()
  }
}

impl<'a, 'b, 'c> Visitor<()> for UnreachableRule<'a, 'b, 'c>
{
    unit_visitor_impl!(atom);
    unit_visitor_impl!(sequence);
    unit_visitor_impl!(non_terminal);

    fn visit_str_literal(&mut self, _this: usize, lit: String){
        if self.in_choice {
            println!("{}",lit.as_str());
            self.current_set.insert(lit);
        }
    }

    fn visit_choice(&mut self, this: usize, children: Vec<usize>){
        self.in_choice = true;
        for child in children {
            self.hash_set_vector.push(self.current_set.iter().cloned().collect());
            self.current_set.clear();
            self.visit_expr(child)
        }
        let len = self.hash_set_vector.len();
        for i in 0..len {
            for j in i+1..len {
                println!("{},{}",i,j);
                if self.hash_set_vector[i].is_superset(&self.hash_set_vector[j]) {
                    self.grammar.span_warn(
                        self.grammar[this].span(),
                        format!("Test")
                    )
                }
            }
        }
        self.hash_set_vector.clear();
        self.in_choice = false
    }
}
<commit_msg>[analysis] Unreachable rule: can detected simple unreachable rule now, with ., /, ;, a<commit_after>// Copyright 2018 Chao Lin & William Sergeant (Sorbonne University)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![macro_use]
use middle::analysis::ast::*;
use self::Pattern::*;
use self::Character::*;

#[derive(Copy, Clone)]
enum Pattern {
  // OneOrMore, // +
  // ZeroOrMore, // *
  // ZeroOrOne, // ?
  One,
  // And, // &
  // Not, // !
}

#[derive(Copy, Clone)]
enum Character{
  Char(char),
  Any // .
}

struct Occurence
{
  choice: Vec<Vec<(Character,Pattern)>>
}

impl Occurence
{
  fn push_sequence(&self, other: Occurence) -> Occurence{
    let mut res = vec![];
    for choice1 in other.choice.clone(){
      for choice2 in self.choice.clone(){
        let mut tmp = choice2.clone();
        for couple in choice1.clone(){
          tmp.push(couple)
        }
        res.push(tmp)
      }
    }
    Occurence{
      choice: res
    }
  }

  fn merge_choice(&self, other: Occurence) -> Occurence {
    let mut res = self.choice.clone();
    for choice in other.choice.clone(){
      res.push(choice)
    }
    Occurence{
      choice: res
    }
  }

  fn copy(&self) -> Occurence{
    Occurence{
      choice: self.choice.to_vec()
    }
  }

  fn is_unreachable_with(&self, target: Occurence) -> bool {
    let mut res = true;
    for seq in self.choice.clone(){
      if !(target.success_with(seq)) {
        res = false;
        break;
      }
    }
    res
  }

  fn success_with(&self, seq2: Vec<(Character, Pattern)>) -> bool {
    let mut res = false;
    for seq1 in self.choice.clone(){
      if self.succeed_before(seq1,seq2.to_vec()) {
        res = true;
      }
    }
    res
  }

  fn succeed_before(&self, seq1: Vec<(Character, Pattern)>, seq2: Vec<(Character, Pattern)>) -> bool{
    let mut res = true;
    if seq2.len()<seq1.len() {
      res=false;
    }
    else{
      for (i,character_pattern1) in seq1.iter().enumerate(){
        if let Some(character_pattern2) = seq2.get(i) {
          let &(c1,_p1) = character_pattern1;
          let &(c2,_p2) = character_pattern2;
          match c1 {
            Char(character1) => {
              match c2 {
                Char(character2) => {
                  if character1!=character2 {
                    res=false;
                    break;
                  }
                }
                Any => {
                  res=false;
                  break;
                }
              }
            }
            Any => { continue; }
          }
        }
      }
    }
    res
  }
}

pub struct UnreachableRule<'a: 'c, 'b: 'a, 'c>
{
  grammar: &'c AGrammar<'a, 'b>
}

impl <'a, 'b, 'c> UnreachableRule<'a, 'b, 'c>
{
  pub fn analyse(grammar: AGrammar<'a, 'b>) -> Partial<AGrammar<'a, 'b>> {
    UnreachableRule::check_unreachable_rule(&grammar);
    Partial::Value(grammar)
  }

  fn check_unreachable_rule(grammar: &'c AGrammar<'a, 'b>){
    let mut analyser = UnreachableRule{
      grammar: grammar
    };

    for rule in &grammar.rules {
      analyser.visit_expr(rule.expr_idx);
    }
  }
}

impl<'a, 'b, 'c> ExprByIndex for UnreachableRule<'a, 'b, 'c>
{
  fn expr_by_index(&self, index: usize) -> Expression {
    self.grammar.expr_by_index(index).clone()
  }
}

impl<'a, 'b, 'c> Visitor<Occurence> for UnreachableRule<'a, 'b, 'c>
{
  fn visit_choice(&mut self, _this: usize, children: Vec<usize>) -> Occurence{
    let mut occurences_of_children = vec![];
    for child in children.clone(){
      let occ = self.visit_expr(child);
      if !occ.choice.is_empty() {
          occurences_of_children.push((occ,child));
      }
    }
    for (i, cp1) in occurences_of_children.iter().enumerate(){
      let (_left, right) = occurences_of_children.split_at(i+1);
      let &(ref occ1, child1) = cp1;
      for cp2 in right{
        let &(ref occ2, child2) = cp2;
        if occ2.is_unreachable_with(occ1.copy()) {
          self.grammar.span_warn(
            self.grammar[child2].span(),
            format!("This rule is unreachable.")
          );
          self.grammar.span_note(
            self.grammar[child1].span(),
            format!("Because this rule succeeded before reading the previous one.")
          );
        }
      }
    }

    let mut res = vec![];
    if let Some((first, rest)) = children.split_first(){
      let mut occ = self.visit_expr(*first);
      for child in rest{
        occ = occ.merge_choice(self.visit_expr(*child))
      }
      res = occ.choice;
    }
    Occurence{
      choice: res
    }
  }

  fn visit_sequence(&mut self, _this: usize, children: Vec<usize>) -> Occurence{
    let mut res = vec![];
    if let Some((first, rest)) = children.split_first(){
      let mut occ = self.visit_expr(*first);
      for child in rest{
        occ = occ.push_sequence(self.visit_expr(*child))
      }
      res = occ.choice;
    }
    Occurence{
      choice: res
    }
  }

  fn visit_atom(&mut self, _this: usize) -> Occurence{
    Occurence{
      choice: vec![]
    }
  }

  fn visit_str_literal(&mut self, _this: usize, lit: String) -> Occurence{
    let mut seq = vec![];
    for c in lit.chars(){
      seq.push((Char(c),One))
    }
    let mut res = vec![];
    res.push(seq);
    Occurence{
      choice: res
    }
  }

  fn visit_any_single_char(&mut self, _this: usize) -> Occurence{
    let mut seq = vec![];
    seq.push((Any,One));
    let mut res = vec![];
    res.push(seq);
    Occurence{
      choice: res
    }
  }

  fn visit_character_class(&mut self, _this: usize, _char_class: CharacterClassExpr) -> Occurence{
    // let mut seq = vec![];
    // for intervals in char_class.intervals{
    //   for intervals.lo to intervals.hi{
    //
    //   }
    // }
    Occurence{
      choice: vec![]
    }
  }

  fn visit_non_terminal_symbol(&mut self, _this: usize, _rule: Ident) -> Occurence{
    Occurence{
      choice: vec![]
    }
  }

  fn visit_zero_or_more(&mut self, _this: usize, _child: usize) -> Occurence{
    Occurence{
      choice: vec![]
    }
  }

  fn visit_one_or_more(&mut self, _this: usize, _child: usize) -> Occurence{
    Occurence{
      choice: vec![]
    }
  }

  fn visit_optional(&mut self, _this: usize, _child: usize) -> Occurence{
    Occurence{
      choice: vec![]
    }
  }

  fn visit_not_predicate(&mut self, _this: usize, _child: usize) -> Occurence{
    Occurence{
      choice: vec![]
    }
  }

  fn visit_and_predicate(&mut self, _this: usize, _child: usize) -> Occurence{
    Occurence{
      choice: vec![]
    }
  }
}
<|endoftext|>


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

#![cfg(test)]

use graph::test::TestGraph;
use super::*;

#[test]
fn diamond() {
    let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]);
    let sccs: Sccs<_, usize> = Sccs::new(&graph);
    assert_eq!(sccs.num_sccs(), 4);
    assert_eq!(sccs.num_sccs(), 4);
}

#[test]
fn test_big_scc() {
    // The order in which things will be visited is important to this
    // test.
    //
    // We will visit:
    //
    // 0 -> 1 -> 2 -> 0
    //
    // and at this point detect a cycle. 2 will return back to 1 which
    // will visit 3. 3 will visit 2 before the cycle is complete, and
    // hence it too will return a cycle.

    /*
+-> 0
|   |
|   v
|   1 -> 3
|   |    |
|   v    |
+-- 2 <--+
     */
    let graph = TestGraph::new(0, &[
        (0, 1),
        (1, 2),
        (1, 3),
        (2, 0),
        (3, 2),
    ]);
    let sccs: Sccs<_, usize> = Sccs::new(&graph);
    assert_eq!(sccs.num_sccs(), 1);
}

#[test]
fn test_three_sccs() {
    /*
    0
    |
    v
+-> 1    3
|   |    |
|   v    |
+-- 2 <--+
     */
    let graph = TestGraph::new(0, &[
        (0, 1),
        (1, 2),
        (2, 1),
        (3, 2),
    ]);
    let sccs: Sccs<_, usize> = Sccs::new(&graph);
    assert_eq!(sccs.num_sccs(), 3);
    assert_eq!(sccs.scc(0), 1);
    assert_eq!(sccs.scc(1), 0);
    assert_eq!(sccs.scc(2), 0);
    assert_eq!(sccs.scc(3), 2);
    assert_eq!(sccs.successors(0), &[]);
    assert_eq!(sccs.successors(1), &[0]);
    assert_eq!(sccs.successors(2), &[0]);
}

#[test]
fn test_find_state_2() {
    // The order in which things will be visited is important to this
    // test. It tests part of the `find_state` behavior.
    //
    // We will start in our DFS by visiting:
    //
    // 0 -> 1 -> 2 -> 1
    //
    // and at this point detect a cycle. The state of 2 will thus be
    // `InCycleWith { 1 }`.  We will then visit the 1 -> 3 edge, which
    // will attempt to visit 0 as well, thus going to the state
    // `InCycleWith { 0 }`. Finally, node 1 will complete; the lowest
    // depth of any successor was 3 which had depth 0, and thus it
    // will be in the state `InCycleWith { 3 }`.
    //
    // When we finally traverse the `0 -> 4` edge and then visit node 2,
    // the states of the nodes are:
    //
    // 0 BeingVisited { 0 }
    // 1 InCycleWith { 3 }
    // 2 InCycleWith { 1 }
    // 3 InCycleWith { 0 }
    //
    // and hence 4 will traverse the links, finding an ultimate depth of 0.
    // If will also collapse the states to the following:
    //
    // 0 BeingVisited { 0 }
    // 1 InCycleWith { 3 }
    // 2 InCycleWith { 1 }
    // 3 InCycleWith { 0 }

    /*
      /----+
    0 <--+ |
    |    | |
    v    | |
+-> 1 -> 3 4
|   |      |
|   v      |
+-- 2 <----+
     */
    let graph = TestGraph::new(0, &[
        (0, 1),
        (0, 4),
        (1, 2),
        (1, 3),
        (2, 1),
        (3, 0),
        (4, 2),
    ]);
    let sccs: Sccs<_, usize> = Sccs::new(&graph);
    assert_eq!(sccs.num_sccs(), 1);
    assert_eq!(sccs.scc(0), 0);
    assert_eq!(sccs.scc(1), 0);
    assert_eq!(sccs.scc(2), 0);
    assert_eq!(sccs.scc(3), 0);
    assert_eq!(sccs.scc(4), 0);
    assert_eq!(sccs.successors(0), &[]);
}

#[test]
fn test_find_state_3() {
    /*
      /----+
    0 <--+ |
    |    | |
    v    | |
+-> 1 -> 3 4 5
|   |      | |
|   v      | |
+-- 2 <----+-+
     */
    let graph = TestGraph::new(0, &[
        (0, 1),
        (0, 4),
        (1, 2),
        (1, 3),
        (2, 1),
        (3, 0),
        (4, 2),
        (5, 2),
    ]);
    let sccs: Sccs<_, usize> = Sccs::new(&graph);
    assert_eq!(sccs.num_sccs(), 2);
    assert_eq!(sccs.scc(0), 0);
    assert_eq!(sccs.scc(1), 0);
    assert_eq!(sccs.scc(2), 0);
    assert_eq!(sccs.scc(3), 0);
    assert_eq!(sccs.scc(4), 0);
    assert_eq!(sccs.scc(5), 1);
    assert_eq!(sccs.successors(0), &[]);
    assert_eq!(sccs.successors(1), &[0]);
}
<commit_msg>nit: tweak comment order<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(test)]

use graph::test::TestGraph;
use super::*;

#[test]
fn diamond() {
    let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]);
    let sccs: Sccs<_, usize> = Sccs::new(&graph);
    assert_eq!(sccs.num_sccs(), 4);
    assert_eq!(sccs.num_sccs(), 4);
}

#[test]
fn test_big_scc() {
    // The order in which things will be visited is important to this
    // test.
    //
    // We will visit:
    //
    // 0 -> 1 -> 2 -> 0
    //
    // and at this point detect a cycle. 2 will return back to 1 which
    // will visit 3. 3 will visit 2 before the cycle is complete, and
    // hence it too will return a cycle.

    /*
+-> 0
|   |
|   v
|   1 -> 3
|   |    |
|   v    |
+-- 2 <--+
     */
    let graph = TestGraph::new(0, &[
        (0, 1),
        (1, 2),
        (1, 3),
        (2, 0),
        (3, 2),
    ]);
    let sccs: Sccs<_, usize> = Sccs::new(&graph);
    assert_eq!(sccs.num_sccs(), 1);
}

#[test]
fn test_three_sccs() {
    /*
    0
    |
    v
+-> 1    3
|   |    |
|   v    |
+-- 2 <--+
     */
    let graph = TestGraph::new(0, &[
        (0, 1),
        (1, 2),
        (2, 1),
        (3, 2),
    ]);
    let sccs: Sccs<_, usize> = Sccs::new(&graph);
    assert_eq!(sccs.num_sccs(), 3);
    assert_eq!(sccs.scc(0), 1);
    assert_eq!(sccs.scc(1), 0);
    assert_eq!(sccs.scc(2), 0);
    assert_eq!(sccs.scc(3), 2);
    assert_eq!(sccs.successors(0), &[]);
    assert_eq!(sccs.successors(1), &[0]);
    assert_eq!(sccs.successors(2), &[0]);
}

#[test]
fn test_find_state_2() {
    // The order in which things will be visited is important to this
    // test. It tests part of the `find_state` behavior. Here is the
    // graph:
    //
    //
    //       /----+
    //     0 <--+ |
    //     |    | |
    //     v    | |
    // +-> 1 -> 3 4
    // |   |      |
    // |   v      |
    // +-- 2 <----+

    let graph = TestGraph::new(0, &[
        (0, 1),
        (0, 4),
        (1, 2),
        (1, 3),
        (2, 1),
        (3, 0),
        (4, 2),
    ]);

    // For this graph, we will start in our DFS by visiting:
    //
    // 0 -> 1 -> 2 -> 1
    //
    // and at this point detect a cycle. The state of 2 will thus be
    // `InCycleWith { 1 }`.  We will then visit the 1 -> 3 edge, which
    // will attempt to visit 0 as well, thus going to the state
    // `InCycleWith { 0 }`. Finally, node 1 will complete; the lowest
    // depth of any successor was 3 which had depth 0, and thus it
    // will be in the state `InCycleWith { 3 }`.
    //
    // When we finally traverse the `0 -> 4` edge and then visit node 2,
    // the states of the nodes are:
    //
    // 0 BeingVisited { 0 }
    // 1 InCycleWith { 3 }
    // 2 InCycleWith { 1 }
    // 3 InCycleWith { 0 }
    //
    // and hence 4 will traverse the links, finding an ultimate depth of 0.
    // If will also collapse the states to the following:
    //
    // 0 BeingVisited { 0 }
    // 1 InCycleWith { 3 }
    // 2 InCycleWith { 1 }
    // 3 InCycleWith { 0 }

    let sccs: Sccs<_, usize> = Sccs::new(&graph);
    assert_eq!(sccs.num_sccs(), 1);
    assert_eq!(sccs.scc(0), 0);
    assert_eq!(sccs.scc(1), 0);
    assert_eq!(sccs.scc(2), 0);
    assert_eq!(sccs.scc(3), 0);
    assert_eq!(sccs.scc(4), 0);
    assert_eq!(sccs.successors(0), &[]);
}

#[test]
fn test_find_state_3() {
    /*
      /----+
    0 <--+ |
    |    | |
    v    | |
+-> 1 -> 3 4 5
|   |      | |
|   v      | |
+-- 2 <----+-+
     */
    let graph = TestGraph::new(0, &[
        (0, 1),
        (0, 4),
        (1, 2),
        (1, 3),
        (2, 1),
        (3, 0),
        (4, 2),
        (5, 2),
    ]);
    let sccs: Sccs<_, usize> = Sccs::new(&graph);
    assert_eq!(sccs.num_sccs(), 2);
    assert_eq!(sccs.scc(0), 0);
    assert_eq!(sccs.scc(1), 0);
    assert_eq!(sccs.scc(2), 0);
    assert_eq!(sccs.scc(3), 0);
    assert_eq!(sccs.scc(4), 0);
    assert_eq!(sccs.scc(5), 1);
    assert_eq!(sccs.successors(0), &[]);
    assert_eq!(sccs.successors(1), &[0]);
}
<|endoftext|>


<commit_before>#![allow(deprecated)]
use std::path::PathBuf;
use std::{io, fs, slice};
use curl::easy::Easy;
use memmap::{Mmap, Protection};
use std::io::{Read, Write};
use utils::data::{DatasetIntfRef, DatasetIntf};
use std::rc::Rc;
use tensor::{Tensor, TensorKind, NumLimits};
use torch;
use std::marker::PhantomData;

type Sample<T> = (Tensor<T>, i64);
type CollatedSample<T> = (Tensor<T>, Tensor<i64>);

static URLS: [&str; 4] = ["http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz"];
static RAW_FOLDER: &str = "raw";
static PROCESSED_FOLDER: &str = "processed";
static TRAINING_FILE: &str = "training.pt";
static TEST_FILE: &str = "test.pt";
static NCHANNELS: isize = 1;

fn create_dir_f(arg: PathBuf) -> io::Result<()> {
    let result = fs::create_dir(arg);
    if let Some(err) = result.err() {
        match err.kind() {
            io::ErrorKind::AlreadyExists => Ok(()),
            _ => Err(err),
        }
    } else {
        Ok(())
    }
}

fn check_exists(arg: &PathBuf) -> io::Result<bool> {
    let train = fs::metadata(arg.join(TRAINING_FILE))?;
    let test = fs::metadata(arg.join(TEST_FILE))?;

    return Ok(train.is_file() && test.is_file());
}

fn download(root: &String) -> io::Result<()> {
    let raw_path = PathBuf::from(root).join(RAW_FOLDER);
    let processed_path = PathBuf::from(root).join(PROCESSED_FOLDER);
    create_dir_f(raw_path.clone())?;
    create_dir_f(processed_path.clone())?;

    for url in URLS.iter() {
        println!("downloading {}", url);
        let paths: Vec<_> = url.split("/").collect();
        let mut fname: Vec<_> = paths[5].split("/").collect();
        fname = fname[0].split(".").collect();
        let file_path = raw_path.join(fname[0]);
        let mut file = fs::OpenOptions::new()
            .write(true)
            .create(true)
            .open(file_path)?;
        let mut data = Vec::new();
        let mut handle = Easy::new();
        handle.url(url).unwrap();
        {
            let mut transfer = handle.transfer();
            transfer
                .write_function(|new_data| {
                                    data.extend_from_slice(new_data);
                                    Ok(new_data.len())
                                })
                .unwrap();
            transfer.perform().unwrap();
        }
        let mut output = Vec::with_capacity(data.len() + 1100000);
        let mut gz = ::flate2::read::GzDecoder::new(data.as_slice())?;
        gz.read_to_end(&mut output)?;

        file.write_all(output.as_slice())?;
    }
    println!("Proceeding");

    let training_set =
        vec![read_image_file(raw_path.join("train-images-idx3-ubyte"))?,
                            read_label_file(raw_path.join("train-labels-idx1-ubyte"))?];
    let test_set = vec![read_image_file(raw_path.join("t10k-images-idx3-ubyte"))?,
                        read_label_file(raw_path.join("t10k-labels-idx1-ubyte"))?];

    torch::save(processed_path.join(TRAINING_FILE), &training_set)?;
    torch::save(processed_path.join(TEST_FILE), &test_set)?;

    Ok(())
}

fn read_image_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let (length, nrows, ncols);
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const i32, fp.len()) };
        assert_eq!(i32::from_be(data[0]), 2051);
        length = i32::from_be(data[1]) as usize;
        nrows = i32::from_be(data[2]) as usize;
        ncols = i32::from_be(data[3]) as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut images: Vec<Vec<u8>> = Vec::with_capacity(length);
    let mut idx = 16;
    // XXX transpose here to be H x W ?
    for _ in 0..length {
        let mut img = Vec::with_capacity(nrows * ncols);
        for _ in 0..nrows * ncols {
            img.push(data[idx]);
            idx += 1;
        }
        images.push(img)
    }
    Ok(torch::byte_tensor(images)
           .view(&[-1, NCHANNELS, 28, 28])
           .into())
}

fn read_label_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let length;
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const i32, fp.len()) };
        assert_eq!(i32::from_be(data[0]), 2049);
        length = i32::from_be(data[1]) as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut labels: Vec<u8> = Vec::with_capacity(length);
    for i in 0..length {
        labels.push(data[8 + i])
    }
    Ok(torch::byte_tensor(labels).into())
}

pub struct MNIST<T: NumLimits> {
    pub root: String,
    pub train: bool,
    pub data: Tensor<u8>,
    pub labels: Tensor<u8>,
    pub transform: Option<Xfrm>,
    phantom: PhantomData<T>,
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct MNISTArgs {
    root: String,
    #[builder(default="true")]
    train: bool,
    #[builder(default="false")]
    download: bool,
}

type Xfrm = Box<fn(&TensorKind) -> TensorKind>;
impl MNISTArgsBuilder {
    pub fn done<T: NumLimits + 'static>(self,
                                        xfrm: Option<Xfrm>)
                                        -> DatasetIntfRef<CollatedSample<T>> {
        let args = self.build().unwrap();
        Rc::new(MNIST::new(args, xfrm))
    }
}

impl<T: NumLimits> MNIST<T> {
    pub fn build(root: &str) -> MNISTArgsBuilder {
        MNISTArgsBuilder::default().root(root.into())
    }
    pub fn new(args: MNISTArgs, xfrm: Option<Xfrm>) -> Self {
        if args.download {
            download(&args.root).expect("download failed");
        }
        let processed_path = PathBuf::from(&args.root).join(PROCESSED_FOLDER);
        if !check_exists(&processed_path).expect("Dataset not found, try downloading") {
            panic!("Dataset not found, use download=true to download it");
        }
        let mut v: Vec<TensorKind> = if args.train {
            torch::load(processed_path.join(TRAINING_FILE)).expect("torch load failed")
        } else {
            torch::load(processed_path.join(TEST_FILE)).expect("torch load failed")
        };
        let (data, labels) = (v.remove(0), v.remove(0));

        MNIST {
            root: args.root.clone(),
            train: args.train,
            data: data.into(),
            labels: labels.into(),
            transform: xfrm,
            phantom: PhantomData,
        }
    }
    fn index(&self, idx: usize) -> Sample<u8> {
        let img = self.data.s([idx]);
        let img = if let Some(ref transform) = self.transform {
            transform(&img.into()).into()
        } else {
            img.clone()
        };
        (img, self.labels[idx].clone() as i64)
    }
}

impl<T: NumLimits> DatasetIntf for MNIST<T> {
    type Batch = CollatedSample<T>;
    fn len(&self) -> usize {
        if self.train { 60000 } else { 10000 }
    }
    fn collate(&self, sample: Vec<usize>) -> Self::Batch {
        println!("collate called len: {}", sample.len());
        let v: Vec<Sample<u8>> = sample.into_iter().map(|i| self.index(i)).collect();
        let labels: Vec<i64> = v.iter().map(|&(_, ref t)| *t).collect();
        let imgs: Vec<Tensor<u8>> = v.into_iter().map(|(d, _)| d).collect();
        // XXX should check for case of double
        let img_batch: Tensor<T> = torch::tensor(imgs);
        let label_batch = torch::long_tensor(labels);
        (img_batch, label_batch)
    }
}
<commit_msg>remove println<commit_after>#![allow(deprecated)]
use std::path::PathBuf;
use std::{io, fs, slice};
use curl::easy::Easy;
use memmap::{Mmap, Protection};
use std::io::{Read, Write};
use utils::data::{DatasetIntfRef, DatasetIntf};
use std::rc::Rc;
use tensor::{Tensor, TensorKind, NumLimits};
use torch;
use std::marker::PhantomData;

type Sample<T> = (Tensor<T>, i64);
type CollatedSample<T> = (Tensor<T>, Tensor<i64>);

static URLS: [&str; 4] = ["http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz",
                          "http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz"];
static RAW_FOLDER: &str = "raw";
static PROCESSED_FOLDER: &str = "processed";
static TRAINING_FILE: &str = "training.pt";
static TEST_FILE: &str = "test.pt";
static NCHANNELS: isize = 1;

fn create_dir_f(arg: PathBuf) -> io::Result<()> {
    let result = fs::create_dir(arg);
    if let Some(err) = result.err() {
        match err.kind() {
            io::ErrorKind::AlreadyExists => Ok(()),
            _ => Err(err),
        }
    } else {
        Ok(())
    }
}

fn check_exists(arg: &PathBuf) -> io::Result<bool> {
    let train = fs::metadata(arg.join(TRAINING_FILE))?;
    let test = fs::metadata(arg.join(TEST_FILE))?;

    return Ok(train.is_file() && test.is_file());
}

fn download(root: &String) -> io::Result<()> {
    let raw_path = PathBuf::from(root).join(RAW_FOLDER);
    let processed_path = PathBuf::from(root).join(PROCESSED_FOLDER);
    create_dir_f(raw_path.clone())?;
    create_dir_f(processed_path.clone())?;

    for url in URLS.iter() {
        println!("downloading {}", url);
        let paths: Vec<_> = url.split("/").collect();
        let mut fname: Vec<_> = paths[5].split("/").collect();
        fname = fname[0].split(".").collect();
        let file_path = raw_path.join(fname[0]);
        let mut file = fs::OpenOptions::new()
            .write(true)
            .create(true)
            .open(file_path)?;
        let mut data = Vec::new();
        let mut handle = Easy::new();
        handle.url(url).unwrap();
        {
            let mut transfer = handle.transfer();
            transfer
                .write_function(|new_data| {
                                    data.extend_from_slice(new_data);
                                    Ok(new_data.len())
                                })
                .unwrap();
            transfer.perform().unwrap();
        }
        let mut output = Vec::with_capacity(data.len() + 1100000);
        let mut gz = ::flate2::read::GzDecoder::new(data.as_slice())?;
        gz.read_to_end(&mut output)?;

        file.write_all(output.as_slice())?;
    }
    println!("Proceeding");

    let training_set =
        vec![read_image_file(raw_path.join("train-images-idx3-ubyte"))?,
                            read_label_file(raw_path.join("train-labels-idx1-ubyte"))?];
    let test_set = vec![read_image_file(raw_path.join("t10k-images-idx3-ubyte"))?,
                        read_label_file(raw_path.join("t10k-labels-idx1-ubyte"))?];

    torch::save(processed_path.join(TRAINING_FILE), &training_set)?;
    torch::save(processed_path.join(TEST_FILE), &test_set)?;

    Ok(())
}

fn read_image_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let (length, nrows, ncols);
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const i32, fp.len()) };
        assert_eq!(i32::from_be(data[0]), 2051);
        length = i32::from_be(data[1]) as usize;
        nrows = i32::from_be(data[2]) as usize;
        ncols = i32::from_be(data[3]) as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut images: Vec<Vec<u8>> = Vec::with_capacity(length);
    let mut idx = 16;
    // XXX transpose here to be H x W ?
    for _ in 0..length {
        let mut img = Vec::with_capacity(nrows * ncols);
        for _ in 0..nrows * ncols {
            img.push(data[idx]);
            idx += 1;
        }
        images.push(img)
    }
    Ok(torch::byte_tensor(images)
           .view(&[-1, NCHANNELS, 28, 28])
           .into())
}

fn read_label_file(path: PathBuf) -> io::Result<TensorKind> {
    let fp = Mmap::open_path(path, Protection::Read)?;
    let length;
    {
        let data = unsafe { slice::from_raw_parts(fp.ptr() as *const i32, fp.len()) };
        assert_eq!(i32::from_be(data[0]), 2049);
        length = i32::from_be(data[1]) as usize;
    }
    let data = unsafe { fp.as_slice() };
    let mut labels: Vec<u8> = Vec::with_capacity(length);
    for i in 0..length {
        labels.push(data[8 + i])
    }
    Ok(torch::byte_tensor(labels).into())
}

pub struct MNIST<T: NumLimits> {
    pub root: String,
    pub train: bool,
    pub data: Tensor<u8>,
    pub labels: Tensor<u8>,
    pub transform: Option<Xfrm>,
    phantom: PhantomData<T>,
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct MNISTArgs {
    root: String,
    #[builder(default="true")]
    train: bool,
    #[builder(default="false")]
    download: bool,
}

type Xfrm = Box<fn(&TensorKind) -> TensorKind>;
impl MNISTArgsBuilder {
    pub fn done<T: NumLimits + 'static>(self,
                                        xfrm: Option<Xfrm>)
                                        -> DatasetIntfRef<CollatedSample<T>> {
        let args = self.build().unwrap();
        Rc::new(MNIST::new(args, xfrm))
    }
}

impl<T: NumLimits> MNIST<T> {
    pub fn build(root: &str) -> MNISTArgsBuilder {
        MNISTArgsBuilder::default().root(root.into())
    }
    pub fn new(args: MNISTArgs, xfrm: Option<Xfrm>) -> Self {
        if args.download {
            download(&args.root).expect("download failed");
        }
        let processed_path = PathBuf::from(&args.root).join(PROCESSED_FOLDER);
        if !check_exists(&processed_path).expect("Dataset not found, try downloading") {
            panic!("Dataset not found, use download=true to download it");
        }
        let mut v: Vec<TensorKind> = if args.train {
            torch::load(processed_path.join(TRAINING_FILE)).expect("torch load failed")
        } else {
            torch::load(processed_path.join(TEST_FILE)).expect("torch load failed")
        };
        let (data, labels) = (v.remove(0), v.remove(0));

        MNIST {
            root: args.root.clone(),
            train: args.train,
            data: data.into(),
            labels: labels.into(),
            transform: xfrm,
            phantom: PhantomData,
        }
    }
    fn index(&self, idx: usize) -> Sample<u8> {
        let img = self.data.s([idx]);
        let img = if let Some(ref transform) = self.transform {
            transform(&img.into()).into()
        } else {
            img.clone()
        };
        (img, self.labels[idx].clone() as i64)
    }
}

impl<T: NumLimits> DatasetIntf for MNIST<T> {
    type Batch = CollatedSample<T>;
    fn len(&self) -> usize {
        if self.train { 60000 } else { 10000 }
    }
    fn collate(&self, sample: Vec<usize>) -> Self::Batch {
        let v: Vec<Sample<u8>> = sample.into_iter().map(|i| self.index(i)).collect();
        let labels: Vec<i64> = v.iter().map(|&(_, ref t)| *t).collect();
        let imgs: Vec<Tensor<u8>> = v.into_iter().map(|(d, _)| d).collect();
        // XXX should check for case of double
        let img_batch: Tensor<T> = torch::tensor(imgs);
        let label_batch = torch::long_tensor(labels);
        (img_batch, label_batch)
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use quote::quote;
use syn::{
    parse::Parser, parse_quote, punctuated::Punctuated, token::Unsafe, Attribute, FnArg,
    ForeignItem, Ident, ImplItem, ReturnType,
};

use super::{
    unqualify::{unqualify_params, unqualify_ret_type},
    RsCodegenResult,
};
use crate::types::make_ident;
use crate::{
    conversion::{
        analysis::fun::{ArgumentAnalysis, FnAnalysisBody},
        api::ImplBlockDetails,
    },
    types::{Namespace, TypeName},
};

pub(crate) fn gen_function(ns: &Namespace, analysis: FnAnalysisBody) -> RsCodegenResult {
    let rename_using_rust_attr = analysis.rename_using_rust_attr;
    let cxxbridge_name = analysis.cxxbridge_name;
    let rust_name = analysis.rust_name;
    let self_ty = analysis.self_ty;
    let ret_type = analysis.ret_type;
    let is_constructor = analysis.is_constructor;
    let param_details = analysis.param_details;
    let cpp_call_name = analysis.cpp_call_name;
    let wrapper_function_needed = analysis.wrapper_function_needed;
    let requires_unsafe = analysis.requires_unsafe;
    let params = analysis.params;
    let vis = analysis.vis;
    // CUT HERE

    let mut cpp_name_attr = Vec::new();
    let mut impl_entry = None;
    if cxxbridge_name != rust_name {
        if let Some(type_name) = &self_ty {
            // Method, or static method.
            impl_entry = Some(generate_method_impl(
                &param_details,
                is_constructor,
                type_name,
                &cxxbridge_name,
                &rust_name,
                &ret_type,
            ));
        }
    }
    let rust_name_attr: Vec<_> = if rename_using_rust_attr {
        Attribute::parse_outer
            .parse2(quote!(
                #[rust_name = #rust_name]
            ))
            .unwrap()
    } else {
        Vec::new()
    };
    if cxxbridge_name != cpp_call_name && !wrapper_function_needed {
        cpp_name_attr = Attribute::parse_outer
            .parse2(quote!(
                #[cxx_name = #cpp_call_name]
            ))
            .unwrap();
    }
    // Finally - namespace support. All the Types in everything
    // above this point are fully qualified. We need to unqualify them.
    // We need to do that _after_ the above wrapper_function_needed
    // work, because it relies upon spotting fully qualified names like
    // std::unique_ptr. However, after it's done its job, all such
    // well-known types should be unqualified already (e.g. just UniquePtr)
    // and the following code will act to unqualify only those types
    // which the user has declared.
    let params = unqualify_params(params);
    let ret_type = unqualify_ret_type(ret_type);
    // And we need to make an attribute for the namespace that the function
    // itself is in.
    let namespace_attr = if ns.is_empty() || wrapper_function_needed {
        Vec::new()
    } else {
        let namespace_string = ns.to_string();
        Attribute::parse_outer
            .parse2(quote!(
                #[namespace = #namespace_string]
            ))
            .unwrap()
    };
    // At last, actually generate the cxx::bridge entry.
    let unsafety: Option<Unsafe> = if requires_unsafe {
        Some(parse_quote!(unsafe))
    } else {
        None
    };
    let extern_c_mod_item = ForeignItem::Fn(parse_quote!(
        #(#namespace_attr)*
        #(#rust_name_attr)*
        #(#cpp_name_attr)*
        #vis #unsafety fn #cxxbridge_name ( #params ) #ret_type;
    ));
    RsCodegenResult {
        extern_c_mod_item: Some(extern_c_mod_item),
        bridge_items: Vec::new(),
        global_items: Vec::new(),
        bindgen_mod_item: None,
        impl_entry,
    }
}

/// Generate an 'impl Type { methods-go-here }' item
fn generate_method_impl(
    param_details: &[ArgumentAnalysis],
    is_constructor: bool,
    impl_block_type_name: &TypeName,
    cxxbridge_name: &Ident,
    rust_name: &str,
    ret_type: &ReturnType,
) -> Box<ImplBlockDetails> {
    let mut wrapper_params: Punctuated<FnArg, syn::Token![,]> = Punctuated::new();
    let mut arg_list = Vec::new();
    for pd in param_details {
        let type_name = pd.conversion.converted_rust_type();
        let wrapper_arg_name = if pd.self_type.is_some() && !is_constructor {
            parse_quote!(self)
        } else {
            pd.name.clone()
        };
        wrapper_params.push(parse_quote!(
            #wrapper_arg_name: #type_name
        ));
        arg_list.push(wrapper_arg_name);
    }

    let rust_name = make_ident(&rust_name);
    Box::new(ImplBlockDetails {
        item: ImplItem::Method(parse_quote! {
            pub fn #rust_name ( #wrapper_params ) #ret_type {
                cxxbridge::#cxxbridge_name ( #(#arg_list),* )
            }
        }),
        ty: make_ident(impl_block_type_name.get_final_ident()),
    })
}
<commit_msg>impls become unsafe if fn is unsafe.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use quote::quote;
use syn::{
    parse::Parser, parse_quote, punctuated::Punctuated, token::Unsafe, Attribute, FnArg,
    ForeignItem, Ident, ImplItem, ReturnType,
};

use super::{
    unqualify::{unqualify_params, unqualify_ret_type},
    RsCodegenResult,
};
use crate::types::make_ident;
use crate::{
    conversion::{
        analysis::fun::{ArgumentAnalysis, FnAnalysisBody},
        api::ImplBlockDetails,
    },
    types::{Namespace, TypeName},
};

pub(crate) fn gen_function(ns: &Namespace, analysis: FnAnalysisBody) -> RsCodegenResult {
    let rename_using_rust_attr = analysis.rename_using_rust_attr;
    let cxxbridge_name = analysis.cxxbridge_name;
    let rust_name = analysis.rust_name;
    let self_ty = analysis.self_ty;
    let ret_type = analysis.ret_type;
    let is_constructor = analysis.is_constructor;
    let param_details = analysis.param_details;
    let cpp_call_name = analysis.cpp_call_name;
    let wrapper_function_needed = analysis.wrapper_function_needed;
    let requires_unsafe = analysis.requires_unsafe;
    let params = analysis.params;
    let vis = analysis.vis;

    let mut cpp_name_attr = Vec::new();
    let mut impl_entry = None;
    let unsafety: Option<Unsafe> = if requires_unsafe {
        Some(parse_quote!(unsafe))
    } else {
        None
    };
    if cxxbridge_name != rust_name {
        if let Some(type_name) = &self_ty {
            // Method, or static method.
            impl_entry = Some(generate_method_impl(
                &param_details,
                is_constructor,
                type_name,
                &cxxbridge_name,
                &rust_name,
                &ret_type,
                &unsafety,
            ));
        }
    }
    let rust_name_attr: Vec<_> = if rename_using_rust_attr {
        Attribute::parse_outer
            .parse2(quote!(
                #[rust_name = #rust_name]
            ))
            .unwrap()
    } else {
        Vec::new()
    };
    if cxxbridge_name != cpp_call_name && !wrapper_function_needed {
        cpp_name_attr = Attribute::parse_outer
            .parse2(quote!(
                #[cxx_name = #cpp_call_name]
            ))
            .unwrap();
    }
    // Finally - namespace support. All the Types in everything
    // above this point are fully qualified. We need to unqualify them.
    // We need to do that _after_ the above wrapper_function_needed
    // work, because it relies upon spotting fully qualified names like
    // std::unique_ptr. However, after it's done its job, all such
    // well-known types should be unqualified already (e.g. just UniquePtr)
    // and the following code will act to unqualify only those types
    // which the user has declared.
    let params = unqualify_params(params);
    let ret_type = unqualify_ret_type(ret_type);
    // And we need to make an attribute for the namespace that the function
    // itself is in.
    let namespace_attr = if ns.is_empty() || wrapper_function_needed {
        Vec::new()
    } else {
        let namespace_string = ns.to_string();
        Attribute::parse_outer
            .parse2(quote!(
                #[namespace = #namespace_string]
            ))
            .unwrap()
    };
    // At last, actually generate the cxx::bridge entry.
    let extern_c_mod_item = ForeignItem::Fn(parse_quote!(
        #(#namespace_attr)*
        #(#rust_name_attr)*
        #(#cpp_name_attr)*
        #vis #unsafety fn #cxxbridge_name ( #params ) #ret_type;
    ));
    RsCodegenResult {
        extern_c_mod_item: Some(extern_c_mod_item),
        bridge_items: Vec::new(),
        global_items: Vec::new(),
        bindgen_mod_item: None,
        impl_entry,
    }
}

/// Generate an 'impl Type { methods-go-here }' item
fn generate_method_impl(
    param_details: &[ArgumentAnalysis],
    is_constructor: bool,
    impl_block_type_name: &TypeName,
    cxxbridge_name: &Ident,
    rust_name: &str,
    ret_type: &ReturnType,
    unsafety: &Option<Unsafe>,
) -> Box<ImplBlockDetails> {
    let mut wrapper_params: Punctuated<FnArg, syn::Token![,]> = Punctuated::new();
    let mut arg_list = Vec::new();
    for pd in param_details {
        let type_name = pd.conversion.converted_rust_type();
        let wrapper_arg_name = if pd.self_type.is_some() && !is_constructor {
            parse_quote!(self)
        } else {
            pd.name.clone()
        };
        wrapper_params.push(parse_quote!(
            #wrapper_arg_name: #type_name
        ));
        arg_list.push(wrapper_arg_name);
    }

    let rust_name = make_ident(&rust_name);
    Box::new(ImplBlockDetails {
        item: ImplItem::Method(parse_quote! {
            pub #unsafety fn #rust_name ( #wrapper_params ) #ret_type {
                cxxbridge::#cxxbridge_name ( #(#arg_list),* )
            }
        }),
        ty: make_ident(impl_block_type_name.get_final_ident()),
    })
}
<|endoftext|>


<commit_before>use Prefab;
use calx_grid;
use errors::*;
use form::Form;
use std::collections::BTreeMap;
use std::fmt;
use std::io;
use std::str::FromStr;
use terrain::Terrain;
use ron;

pub fn save_prefab<W: io::Write>(output: &mut W, prefab: &Prefab) -> Result<()> {
    const ALPHABET: &'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\
             abcdefghijklmnopqrstuvwxyz\
             0123456789";

    let chars_f = move |x: &(Terrain, Vec<String>)| {
        let &(ref t, ref e) = x;
        if e.is_empty() {
            t.preferred_map_chars()
        } else {
            ""
        }
    };

    let mut legend_builder = calx_grid::LegendBuilder::new(ALPHABET.to_string(), chars_f);

    let prefab = prefab.clone().map(|e| legend_builder.add(&e));
    // Values are still results, we need to check if legend building failed.
    if legend_builder.out_of_alphabet {
        return Err("Unable to build legend, scene too complex?".into());
    }

    // Mustn't have non-errs in the build prefab unless out_of_alphabet was flipped.
    let prefab = prefab.map(|e| e.unwrap());

    let legend = legend_builder
        .legend
        .into_iter()
        .map(|(c, t)| {
            (
                c,
                LegendItem {
                    t: format!("{:?}", t.0),
                    e: t.1.clone(),
                },
            )
        })
        .collect::<BTreeMap<char, LegendItem>>();

    let save = MapSave {
        map: format!("{}", prefab.hexmap_display()),
        legend: legend,
    };

    write!(output, "{}", ron::ser::to_string(&save)?)?;
    Ok(())
}

pub fn load_prefab<I: io::Read>(input: &mut I) -> Result<Prefab> {
    let mut s = String::new();
    input.read_to_string(&mut s)?;
    let save: MapSave = ron::de::from_str(&s)?;

    // Validate the prefab
    for i in save.legend.values() {
        if Terrain::from_str(&i.t).is_err() {
            return Err(format!("Unknown terrain type '{}'", i.t).into());
        }

        for e in &i.e {
            if Form::named(e).is_none() {
                return Err(format!("Unknown entity spawn '{}'", e).into());
            }
        }
    }
    for c in save.map.chars() {
        if c.is_whitespace() {
            continue;
        }
        if !save.legend.contains_key(&c) {
            return Err(format!("Unknown map character '{}'", c).into());
        }
    }

    // Turn map into prefab.
    let prefab: calx_grid::Prefab<char> = calx_grid::Prefab::from_text_hexmap(&save.map);
    Ok(prefab.map(|item| {
        let e = &save.legend[&item];
        let terrain = Terrain::from_str(&e.t).unwrap();
        let spawns = e.e.clone();
        (terrain, spawns)
    }))
}

/// Type for maps saved into disk.
#[derive(Debug, Serialize, Deserialize)]
struct MapSave {
    pub map: String,
    pub legend: BTreeMap<char, LegendItem>,
}

#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
struct LegendItem {
    /// Terrain
    pub t: String,
    /// Entities
    pub e: Vec<String>,
}
<commit_msg>Migrate to new mapfile schema<commit_after>use Prefab;
use calx_grid;
use errors::*;
use form::Form;
use std::collections::BTreeMap;
use std::fmt;
use std::io;
use std::str::FromStr;
use terrain::Terrain;
use ron;

pub fn save_prefab<W: io::Write>(output: &mut W, prefab: &Prefab) -> Result<()> {
    const ALPHABET: &'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\
             abcdefghijklmnopqrstuvwxyz\
             0123456789";

    let chars_f = move |x: &(Terrain, Vec<String>)| {
        let &(ref t, ref e) = x;
        if e.is_empty() {
            t.preferred_map_chars()
        } else {
            ""
        }
    };

    let mut legend_builder = calx_grid::LegendBuilder::new(ALPHABET.to_string(), chars_f);

    let prefab = prefab.clone().map(|e| legend_builder.add(&e));
    // Values are still results, we need to check if legend building failed.
    if legend_builder.out_of_alphabet {
        return Err("Unable to build legend, scene too complex?".into());
    }

    // Mustn't have non-errs in the build prefab unless out_of_alphabet was flipped.
    let prefab = prefab.map(|e| e.unwrap());

    let map = format!("{}", prefab.hexmap_display());
    let legend = legend_builder.legend;

    write!(output, "{}", ron::ser::to_string(&MapSave { map, legend })?)?;
    Ok(())
}

pub fn load_prefab<I: io::Read>(input: &mut I) -> Result<Prefab> {
    let mut s = String::new();
    input.read_to_string(&mut s)?;
    let save_old: MapSaveOld = ron::de::from_str(&s)?;
    let save = MapSave {
        map: save_old.map,
        legend: save_old.legend.into_iter().map(|(k, v)| (k, (Terrain::from_str(&v.t).unwrap(), v.e))).collect()
    };

    // Validate the prefab
    for i in save.legend.values() {
        for e in &i.1 {
            if Form::named(e).is_none() {
                return Err(format!("Unknown entity spawn '{}'", e).into());
            }
        }
    }
    for c in save.map.chars() {
        if c.is_whitespace() {
            continue;
        }
        if !save.legend.contains_key(&c) {
            return Err(format!("Unknown map character '{}'", c).into());
        }
    }

    // Turn map into prefab.
    let prefab: calx_grid::Prefab<char> = calx_grid::Prefab::from_text_hexmap(&save.map);
    Ok(prefab.map(|item| { save.legend[&item].clone() }))
}

/// Type for maps saved into disk.
#[derive(Debug, Serialize, Deserialize)]
struct MapSaveOld {
    pub map: String,
    pub legend: BTreeMap<char, LegendItem>,
}

#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
struct LegendItem {
    /// Terrain
    pub t: String,
    /// Entities
    pub e: Vec<String>,
}

#[derive(Debug, Serialize, Deserialize)]
struct MapSave {
    pub map: String,
    pub legend: BTreeMap<char, (Terrain, Vec<String>)>,
}
<|endoftext|>