[librsvg: 14/95] Port PropertyBag to Rust



commit 22281aa8ee30a00b8de165f7f227f3b6e035662e
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Feb 12 14:55:31 2018 -0600

    Port PropertyBag to Rust
    
    This is a HashMap for now, to match the C version which used a
    GHashTable.  Eventually its implementation will only be a wrapper for
    the (char **) from libxml2, plus an iterator over the key/value pairs
    in such an array.  For now, we do need lookup() semantics.  We will be
    moving the set_atts() methods to iteration instead of lookups one by
    one.

 rsvg-base.c              |  12 ++--
 rsvg-filter.c            |  40 +++++------
 rsvg-private.h           |  30 +++++---
 rsvg-styles.c            |  77 --------------------
 rsvg-text.c              |   6 +-
 rust/src/cnode.rs        |   4 +-
 rust/src/lib.rs          |   8 +++
 rust/src/node.rs         |  13 ++--
 rust/src/property_bag.rs | 180 +++++++++++++++++++++++++++++++++++++----------
 rust/src/stop.rs         |   4 +-
 rust/src/structure.rs    |  14 ++--
 11 files changed, 219 insertions(+), 169 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index c8da9c26..3fe71f01 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -145,7 +145,7 @@ rsvg_style_handler_characters (RsvgSaxHandler * self, const char *ch, gssize len
 }
 
 static void
-rsvg_style_handler_start (RsvgSaxHandler * self, const char *name, RsvgPropertyBag * atts)
+rsvg_style_handler_start (RsvgSaxHandler * self, const char *name, RsvgPropertyBag atts)
 {
 }
 
@@ -388,7 +388,7 @@ get_node_creator_for_element_name (const char *name)
 }
 
 static void
-node_set_atts (RsvgNode * node, RsvgHandle *handle, const NodeCreator *creator, RsvgPropertyBag * atts)
+node_set_atts (RsvgNode * node, RsvgHandle *handle, const NodeCreator *creator, RsvgPropertyBag atts)
 {
     if (rsvg_property_bag_size (atts) > 0) {
         const char *id;
@@ -482,7 +482,7 @@ rsvg_extra_handler_characters (RsvgSaxHandler * self, const char *ch, gssize len
 }
 
 static void
-rsvg_extra_handler_start (RsvgSaxHandler * self, const char *name, RsvgPropertyBag * atts)
+rsvg_extra_handler_start (RsvgSaxHandler * self, const char *name, RsvgPropertyBag atts)
 {
 }
 
@@ -560,7 +560,7 @@ rsvg_metadata_props_enumerate (const char *key, const char *value, gpointer user
 }
 
 static void
-rsvg_metadata_handler_start (RsvgSaxHandler * self, const char *name, RsvgPropertyBag * atts)
+rsvg_metadata_handler_start (RsvgSaxHandler * self, const char *name, RsvgPropertyBag atts)
 {
     RsvgSaxHandlerMetadata *z = (RsvgSaxHandlerMetadata *) self;
 
@@ -629,7 +629,7 @@ rsvg_xinclude_handler_characters (RsvgSaxHandler * self, const char *ch, gssize
 }
 
 static void
-rsvg_xinclude_handler_start (RsvgSaxHandler * self, const char *name, RsvgPropertyBag * atts)
+rsvg_xinclude_handler_start (RsvgSaxHandler * self, const char *name, RsvgPropertyBag atts)
 {
     RsvgSaxHandlerXinclude *z = (RsvgSaxHandlerXinclude *) self;
 
@@ -805,7 +805,7 @@ rsvg_start_xinclude (RsvgHandle *handle, RsvgPropertyBag * atts)
 static void
 rsvg_start_element (void *data, const xmlChar * name, const xmlChar ** atts)
 {
-    RsvgPropertyBag *bag;
+    RsvgPropertyBag bag;
     RsvgHandle *handle = (RsvgHandle *) data;
 
     bag = rsvg_property_bag_new ((const char **) atts);
diff --git a/rsvg-filter.c b/rsvg-filter.c
index 0a6e0f89..8421a8bc 100644
--- a/rsvg-filter.c
+++ b/rsvg-filter.c
@@ -790,7 +790,7 @@ rsvg_filter_get_in (GString * name, RsvgFilterContext * ctx)
 }
 
 static void
-rsvg_filter_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
+rsvg_filter_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
 {
     RsvgFilter *filter = impl;
     const char *value;
@@ -1041,7 +1041,7 @@ rsvg_filter_primitive_blend_free (gpointer impl)
 }
 
 static void
-rsvg_filter_primitive_blend_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
*atts)
+rsvg_filter_primitive_blend_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
atts)
 {
     RsvgFilterPrimitiveBlend *filter = impl;
     const char *value;
@@ -1255,7 +1255,7 @@ rsvg_filter_primitive_convolve_matrix_free (gpointer impl)
 }
 
 static void
-rsvg_filter_primitive_convolve_matrix_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag *atts)
+rsvg_filter_primitive_convolve_matrix_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag atts)
 {
     RsvgFilterPrimitiveConvolveMatrix *filter = impl;
     gint i, j;
@@ -2009,7 +2009,7 @@ rsvg_filter_primitive_gaussian_blur_render (RsvgNode *node, RsvgFilterPrimitive
 }
 
 static void
-rsvg_filter_primitive_gaussian_blur_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag *atts)
+rsvg_filter_primitive_gaussian_blur_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag atts)
 {
     RsvgFilterPrimitiveGaussianBlur *filter = impl;
     const char *value;
@@ -2134,7 +2134,7 @@ rsvg_filter_primitive_offset_render (RsvgNode *node, RsvgFilterPrimitive *primit
 }
 
 static void
-rsvg_filter_primitive_offset_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag * 
atts)
+rsvg_filter_primitive_offset_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
atts)
 {
     RsvgFilterPrimitiveOffset *filter = impl;
     const char *value;
@@ -2240,7 +2240,7 @@ rsvg_filter_primitive_merge_render (RsvgNode *node, RsvgFilterPrimitive *primiti
 }
 
 static void
-rsvg_filter_primitive_merge_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
*atts)
+rsvg_filter_primitive_merge_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
atts)
 {
     RsvgFilterPrimitiveMerge *filter = impl;
     const char *value;
@@ -2270,7 +2270,7 @@ rsvg_new_filter_primitive_merge (const char *element_name, RsvgNode *parent)
 }
 
 static void
-rsvg_filter_primitive_merge_node_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag *atts)
+rsvg_filter_primitive_merge_node_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag atts)
 {
     RsvgFilterPrimitive *primitive = impl;
     const char *value;
@@ -2419,7 +2419,7 @@ rsvg_filter_primitive_color_matrix_free (gpointer impl)
 }
 
 static void
-rsvg_filter_primitive_color_matrix_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag *atts)
+rsvg_filter_primitive_color_matrix_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag atts)
 {
     RsvgFilterPrimitiveColorMatrix *filter = impl;
     gint type;
@@ -2755,7 +2755,7 @@ rsvg_filter_primitive_component_transfer_render (RsvgNode *node, RsvgFilterPrimi
 }
 
 static void
-rsvg_filter_primitive_component_transfer_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag *atts)
+rsvg_filter_primitive_component_transfer_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag atts)
 {
     RsvgFilterPrimitiveComponentTransfer *filter = impl;
     const char *value;
@@ -2788,7 +2788,7 @@ rsvg_new_filter_primitive_component_transfer (const char *element_name, RsvgNode
 }
 
 static void
-rsvg_node_component_transfer_function_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag *atts)
+rsvg_node_component_transfer_function_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag atts)
 {
     RsvgNodeComponentTransferFunc *data = impl;
     const char *value;
@@ -2979,7 +2979,7 @@ rsvg_filter_primitive_erode_render (RsvgNode *node, RsvgFilterPrimitive *primiti
 }
 
 static void
-rsvg_filter_primitive_erode_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
*atts)
+rsvg_filter_primitive_erode_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
atts)
 {
     RsvgFilterPrimitiveErode *filter = impl;
     const char *value;
@@ -3184,7 +3184,7 @@ rsvg_filter_primitive_composite_free (gpointer impl)
 }
 
 static void
-rsvg_filter_primitive_composite_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
*atts)
+rsvg_filter_primitive_composite_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
atts)
 {
     RsvgFilterPrimitiveComposite *filter = impl;
     const char *value;
@@ -3301,7 +3301,7 @@ rsvg_filter_primitive_flood_render (RsvgNode *node, RsvgFilterPrimitive *primiti
 }
 
 static void
-rsvg_filter_primitive_flood_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
*atts)
+rsvg_filter_primitive_flood_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
atts)
 {
     RsvgFilterPrimitive *filter = impl;
     const char *value;
@@ -3472,7 +3472,7 @@ rsvg_filter_primitive_displacement_map_free (gpointer impl)
 }
 
 static void
-rsvg_filter_primitive_displacement_map_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag *atts)
+rsvg_filter_primitive_displacement_map_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag atts)
 {
     RsvgFilterPrimitiveDisplacementMap *filter = impl;
     const char *value;
@@ -3834,7 +3834,7 @@ rsvg_filter_primitive_turbulence_render (RsvgNode *node, RsvgFilterPrimitive *pr
 }
 
 static void
-rsvg_filter_primitive_turbulence_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag *atts)
+rsvg_filter_primitive_turbulence_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag atts)
 {
     RsvgFilterPrimitiveTurbulence *filter = impl;
     const char *value;
@@ -4055,7 +4055,7 @@ rsvg_filter_primitive_image_free (gpointer impl)
 }
 
 static void
-rsvg_filter_primitive_image_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
*atts)
+rsvg_filter_primitive_image_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
atts)
 {
     RsvgFilterPrimitiveImage *filter = impl;
     const char *value;
@@ -4443,7 +4443,7 @@ get_light_color (RsvgNodeLightSource * source, vector3 color,
 
 
 static void
-rsvg_node_light_source_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
+rsvg_node_light_source_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
 {
     RsvgNodeLightSource *data = impl;
     const char *value;
@@ -4645,7 +4645,7 @@ rsvg_filter_primitive_diffuse_lighting_render (RsvgNode *node, RsvgFilterPrimiti
 }
 
 static void
-rsvg_filter_primitive_diffuse_lighting_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag *atts)
+rsvg_filter_primitive_diffuse_lighting_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag atts)
 {
     RsvgFilterPrimitiveDiffuseLighting *filter = impl;
     const char *value;
@@ -4835,7 +4835,7 @@ rsvg_filter_primitive_specular_lighting_render (RsvgNode *node, RsvgFilterPrimit
 }
 
 static void
-rsvg_filter_primitive_specular_lighting_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag *atts)
+rsvg_filter_primitive_specular_lighting_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, 
RsvgPropertyBag atts)
 {
     RsvgFilterPrimitiveSpecularLighting *filter = impl;
     const char *value;
@@ -4987,7 +4987,7 @@ rsvg_filter_primitive_tile_render (RsvgNode *node, RsvgFilterPrimitive *primitiv
 }
 
 static void
-rsvg_filter_primitive_tile_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag 
*atts)
+rsvg_filter_primitive_tile_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
 {
     RsvgFilterPrimitiveTile *filter = impl;
     const char *value;
diff --git a/rsvg-private.h b/rsvg-private.h
index cc2c700f..995ad8b9 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -48,7 +48,7 @@ G_BEGIN_DECLS
 typedef struct RsvgSaxHandler RsvgSaxHandler;
 typedef struct RsvgDrawingCtx RsvgDrawingCtx;
 typedef struct RsvgRender RsvgRender;
-typedef GHashTable RsvgPropertyBag;
+typedef void   *RsvgPropertyBag;
 typedef struct _RsvgState RsvgState;
 typedef struct _RsvgDefs RsvgDefs;
 typedef struct _RsvgNode RsvgNode;
@@ -117,7 +117,7 @@ typedef struct _RsvgFilter RsvgFilter;
 
 struct RsvgSaxHandler {
     void (*free) (RsvgSaxHandler * self);
-    void (*start_element) (RsvgSaxHandler * self, const char *name, RsvgPropertyBag * atts);
+    void (*start_element) (RsvgSaxHandler * self, const char *name, RsvgPropertyBag atts);
     void (*end_element) (RsvgSaxHandler * self, const char *name);
     void (*characters) (RsvgSaxHandler * self, const char *ch, gssize len);
 };
@@ -342,7 +342,7 @@ typedef enum {
     RSVG_NODE_TYPE_FILTER_PRIMITIVE_LAST                /* just a marker; not a valid type */
 } RsvgNodeType;
 
-typedef void (* CNodeSetAtts) (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *pbag);
+typedef void (* CNodeSetAtts) (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag pbag);
 typedef void (* CNodeDraw) (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate);
 typedef void (* CNodeFree) (gpointer impl);
 
@@ -397,7 +397,7 @@ void rsvg_node_add_child (RsvgNode *node, RsvgNode *child);
 
 /* Implemented in rust/src/node.rs */
 G_GNUC_INTERNAL
-void rsvg_node_set_atts (RsvgNode *node, RsvgHandle *handle, RsvgPropertyBag *atts);
+void rsvg_node_set_atts (RsvgNode *node, RsvgHandle *handle, RsvgPropertyBag atts);
 
 /* Implemented in rust/src/node.rs */
 G_GNUC_INTERNAL
@@ -430,18 +430,26 @@ void rsvg_node_chars_get_string (RsvgNode *node, const char **out_str, gsize *ou
 
 typedef void (*RsvgPropertyBagEnumFunc) (const char *key, const char *value, gpointer user_data);
 
+/* Implemented in rust/src/property_bag.rs */
 G_GNUC_INTERNAL
-RsvgPropertyBag            *rsvg_property_bag_new       (const char **atts);
-G_GNUC_INTERNAL
-RsvgPropertyBag            *rsvg_property_bag_dup       (RsvgPropertyBag * bag);
+RsvgPropertyBag            rsvg_property_bag_new       (const char **atts);
+
+/* Implemented in rust/src/property_bag.rs */
 G_GNUC_INTERNAL
-void                 rsvg_property_bag_free      (RsvgPropertyBag * bag);
+void                 rsvg_property_bag_free      (RsvgPropertyBag bag);
+
+/* Implemented in rust/src/property_bag.rs */
 G_GNUC_INTERNAL
-const char          *rsvg_property_bag_lookup    (RsvgPropertyBag * bag, const char *key);
+const char          *rsvg_property_bag_lookup    (RsvgPropertyBag bag, const char *key);
+
+/* Implemented in rust/src/property_bag.rs */
 G_GNUC_INTERNAL
-guint                rsvg_property_bag_size         (RsvgPropertyBag * bag);
+guint                rsvg_property_bag_size         (RsvgPropertyBag bag);
+
+/* Implemented in rust/src/property_bag.rs */
 G_GNUC_INTERNAL
-void                 rsvg_property_bag_enumerate (RsvgPropertyBag * bag, RsvgPropertyBagEnumFunc func,
+void                 rsvg_property_bag_enumerate (RsvgPropertyBag bag,
+                                                  RsvgPropertyBagEnumFunc func,
                                                   gpointer user_data);
 /* for some reason this one's public... */
 GdkPixbuf *rsvg_pixbuf_from_data_with_size_data (const guchar * buff,
diff --git a/rsvg-styles.c b/rsvg-styles.c
index a16c789e..cec664c1 100644
--- a/rsvg-styles.c
+++ b/rsvg-styles.c
@@ -1676,83 +1676,6 @@ rsvg_state_free_all (RsvgState * state)
     }
 }
 
-/**
- * rsvg_property_bag_new:
- * @atts: (array zero-terminated=1): list of alternating attributes
- *   and values
- * 
- * The property bag will NOT copy the attributes and values. If you need
- * to store them for later, use rsvg_property_bag_dup().
- * 
- * Returns: (transfer full): a new property bag
- */
-RsvgPropertyBag *
-rsvg_property_bag_new (const char **atts)
-{
-    RsvgPropertyBag *bag;
-    int i;
-
-    bag = g_hash_table_new (g_str_hash, g_str_equal);
-
-    if (atts != NULL) {
-        for (i = 0; atts[i] != NULL; i += 2)
-            g_hash_table_insert (bag, (gpointer) atts[i], (gpointer) atts[i + 1]);
-    }
-
-    return bag;
-}
-
-/**
- * rsvg_property_bag_dup:
- * @bag: property bag to duplicate
- * 
- * Returns a copy of @bag that owns the attributes and values.
- * 
- * Returns: (transfer full): a new property bag
- */
-RsvgPropertyBag *
-rsvg_property_bag_dup (RsvgPropertyBag * bag)
-{
-    RsvgPropertyBag *dup;
-    GHashTableIter iter;
-    gpointer key, value;
-
-    dup = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-
-    g_hash_table_iter_init (&iter, bag);
-    while (g_hash_table_iter_next (&iter, &key, &value))
-      g_hash_table_insert (dup, 
-                           (gpointer) g_strdup ((char *) key),
-                           (gpointer) g_strdup ((char *) value));
-
-    return dup;
-}
-
-void
-rsvg_property_bag_free (RsvgPropertyBag * bag)
-{
-    g_hash_table_unref (bag);
-}
-
-const char *
-rsvg_property_bag_lookup (RsvgPropertyBag * bag, const char *key)
-{
-    return (const char *) g_hash_table_lookup (bag, (gconstpointer) key);
-}
-
-guint
-rsvg_property_bag_size (RsvgPropertyBag * bag)
-{
-    return g_hash_table_size (bag);
-}
-
-void
-rsvg_property_bag_enumerate (RsvgPropertyBag * bag, RsvgPropertyBagEnumFunc func,
-                             gpointer user_data)
-{
-    g_hash_table_foreach (bag, (GHFunc) func, user_data);
-}
-
 void
 rsvg_state_push (RsvgDrawingCtx * ctx)
 {
diff --git a/rsvg-text.c b/rsvg-text.c
index 3c69cd9d..e17dab38 100644
--- a/rsvg-text.c
+++ b/rsvg-text.c
@@ -81,7 +81,7 @@ set_text_common_atts (RsvgNodeText *text, RsvgPropertyBag *atts)
 
 
 static void
-rsvg_node_text_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
+rsvg_node_text_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
 {
     RsvgNodeText *text = impl;
 
@@ -433,7 +433,7 @@ length_from_tspan (RsvgNode       *node,
 }
 
 static void
-rsvg_node_tspan_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
+rsvg_node_tspan_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
 {
     RsvgNodeText *text = impl;
 
@@ -515,7 +515,7 @@ rsvg_node_tref_free (gpointer impl)
 }
 
 static void
-rsvg_node_tref_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
+rsvg_node_tref_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
 {
     RsvgNodeTref *text = impl;
     const char *value;
diff --git a/rust/src/cnode.rs b/rust/src/cnode.rs
index b8afecef..3b6be21a 100644
--- a/rust/src/cnode.rs
+++ b/rust/src/cnode.rs
@@ -1,12 +1,12 @@
 use drawing_ctx::RsvgDrawingCtx;
 use handle::*;
 use node::*;
-use property_bag::{FfiRsvgPropertyBag, PropertyBag};
+use property_bag::PropertyBag;
 use state::RsvgState;
 
 use std::rc::*;
 
-type CNodeSetAtts = unsafe extern "C" fn (node: *const RsvgNode, node_impl: *const RsvgCNodeImpl, handle: 
*const RsvgHandle, pbag: FfiRsvgPropertyBag);
+type CNodeSetAtts = unsafe extern "C" fn (node: *const RsvgNode, node_impl: *const RsvgCNodeImpl, handle: 
*const RsvgHandle, pbag: *const PropertyBag);
 type CNodeDraw = unsafe extern "C" fn (node: *const RsvgNode, node_impl: *const RsvgCNodeImpl, draw_ctx: 
*const RsvgDrawingCtx, dominate: i32);
 type CNodeFree = unsafe extern "C" fn (node_impl: *const RsvgCNodeImpl);
 
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index d5b5bcd8..0179834a 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -130,6 +130,14 @@ pub use pattern::{
     pattern_resolve_fallbacks_and_set_pattern,
 };
 
+pub use property_bag::{
+    rsvg_property_bag_enumerate,
+    rsvg_property_bag_free,
+    rsvg_property_bag_lookup,
+    rsvg_property_bag_new,
+    rsvg_property_bag_size,
+};
+
 pub use shapes::{
     rsvg_node_circle_new,
     rsvg_node_ellipse_new,
diff --git a/rust/src/node.rs b/rust/src/node.rs
index 443dc808..d3058c12 100644
--- a/rust/src/node.rs
+++ b/rust/src/node.rs
@@ -12,7 +12,7 @@ use drawing_ctx;
 use error::*;
 use handle::RsvgHandle;
 use parsers::ParseError;
-use property_bag::{FfiRsvgPropertyBag, PropertyBag};
+use property_bag::PropertyBag;
 use state::RsvgState;
 
 /* A *const RsvgNode is just a pointer for the C code's benefit: it
@@ -361,13 +361,14 @@ pub extern fn rsvg_node_add_child (raw_node: *mut RsvgNode, raw_child: *const Rs
 #[no_mangle]
 pub extern fn rsvg_node_set_atts (raw_node: *mut RsvgNode,
                                   handle: *const RsvgHandle,
-                                  ffi_pbag: FfiRsvgPropertyBag) {
-    assert! (!raw_node.is_null ());
-    let node: &RsvgNode = unsafe { & *raw_node };
+                                  pbag: *const PropertyBag) {
+    assert!(!raw_node.is_null());
+    assert!(!pbag.is_null());
 
-    let pbag = PropertyBag::new(ffi_pbag);
+    let node: &RsvgNode = unsafe { & *raw_node };
+    let pbag = unsafe { &*pbag };
 
-    node.set_atts (node, handle, &pbag);
+    node.set_atts(node, handle, &pbag);
 }
 
 #[no_mangle]
diff --git a/rust/src/property_bag.rs b/rust/src/property_bag.rs
index 8671dec7..de509f1b 100644
--- a/rust/src/property_bag.rs
+++ b/rust/src/property_bag.rs
@@ -1,60 +1,132 @@
-use glib::translate::*;
 use libc;
 
+use std::collections::HashMap;
+use std::ffi::{CStr, CString};
+use std::ops::Deref;
+use std::ptr;
+
 use error::*;
 use parsers::Parse;
-use util::utf8_cstr;
 
-pub type FfiRsvgPropertyBag = *mut libc::c_void;
+pub struct PropertyBag<'a>(HashMap<&'a CStr, &'a CStr>);
 
-pub enum PropertyBag {
-    Borrowed(FfiRsvgPropertyBag),
-    Owned(FfiRsvgPropertyBag)
-}
+pub struct OwnedPropertyBag(HashMap<CString, CString>);
 
-extern "C" {
-    fn rsvg_property_bag_lookup (pbag: FfiRsvgPropertyBag, key: *const libc::c_char) -> *const libc::c_char;
-    fn rsvg_property_bag_dup (pbag: FfiRsvgPropertyBag) -> FfiRsvgPropertyBag;
-    fn rsvg_property_bag_free (pbag: FfiRsvgPropertyBag);
-}
+impl<'a> PropertyBag<'a> {
+    pub unsafe fn new_from_key_value_pairs(pairs: *const *const libc::c_char) -> PropertyBag<'a> {
+        let mut map = HashMap::new();
+
+        if !pairs.is_null() {
+            let mut i = 0;
+            loop {
+                let key = *pairs.offset(i);
+                if !key.is_null() {
+                    let val = *pairs.offset(i + 1);
+                    assert!(!val.is_null());
+
+                    let key_str = CStr::from_ptr(key);
+                    let val_str = CStr::from_ptr(val);
+
+                    map.insert(key_str, val_str);
+                } else {
+                    break;
+                }
 
-impl PropertyBag {
-    pub fn new(ffi: FfiRsvgPropertyBag) -> PropertyBag {
-        PropertyBag::Borrowed(ffi)
+                i += 2;
+            }
+        }
+
+        PropertyBag(map)
     }
 
-    pub fn ffi(&self) -> FfiRsvgPropertyBag {
-        match self {
-            &PropertyBag::Borrowed(ffi) => ffi,
-            &PropertyBag::Owned(ffi) => ffi
+    pub fn from_owned(owned: &OwnedPropertyBag) -> PropertyBag {
+        let mut map = HashMap::new();
+
+        for (k, v) in &owned.0 {
+            map.insert(k.deref(), v.deref());
         }
+
+        PropertyBag(map)
     }
 
-    pub fn dup(&self) -> PropertyBag {
-        unsafe {
-            PropertyBag::Owned(rsvg_property_bag_dup(self.ffi()))
+    pub fn to_owned(&self) -> OwnedPropertyBag {
+        let mut map = HashMap::<CString, CString>::new();
+
+        for (k, v) in &self.0 {
+            map.insert((*k).to_owned(), (*v).to_owned());
         }
+
+        OwnedPropertyBag(map)
+    }
+
+    pub fn ffi(&self) -> *const PropertyBag {
+        self as *const PropertyBag
+    }
+
+    pub fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    pub fn lookup_cstr(&self, key: &CStr) -> Option<&CStr> {
+        self.0.get(key).map(|v| *v)
     }
 
     pub fn lookup(&self, key: &str) -> Option<&str> {
-        let ffi = self.ffi();
-
-        unsafe {
-            let c_value = rsvg_property_bag_lookup (ffi, key.to_glib_none ().0);
-            if c_value.is_null() {
-                None
-            } else {
-                Some(utf8_cstr(c_value))
-            }
+        let k = CString::new(key).unwrap();
+        self.lookup_cstr(&k).map(|v| v.to_str().unwrap())
+    }
+
+    pub fn enumerate(&self,
+                 enum_fn: fn (key: *const libc::c_char, val: *const libc::c_char, data: *const libc::c_void),
+                 data: *const libc::c_void) {
+        for (k, v) in &self.0 {
+            enum_fn(k.as_ptr(), v.as_ptr(), data);
         }
     }
 }
 
-impl Drop for PropertyBag {
-    fn drop(&mut self) {
-        match *self {
-            PropertyBag::Borrowed(_) => (),
-            PropertyBag::Owned(ffi) => unsafe { rsvg_property_bag_free(ffi) }
+#[no_mangle]
+pub extern fn rsvg_property_bag_new<'a>(atts: *const *const libc::c_char) -> *const PropertyBag<'a> {
+    let pbag = unsafe { PropertyBag::new_from_key_value_pairs(atts) };
+    Box::into_raw(Box::new(pbag))
+}
+
+#[no_mangle]
+pub extern fn rsvg_property_bag_free(pbag: *mut PropertyBag) {
+    unsafe {
+        let _ = Box::from_raw(pbag);
+    }
+}
+
+#[no_mangle]
+pub extern fn rsvg_property_bag_size(pbag: *const PropertyBag) -> libc::c_uint {
+    unsafe {
+        let pbag = &*pbag;
+
+        pbag.len() as libc::c_uint
+    }
+}
+
+#[no_mangle]
+pub extern fn rsvg_property_bag_enumerate(pbag: *const PropertyBag,
+                                          enum_fn: fn (key: *const libc::c_char, val: *const libc::c_char, 
data: *const libc::c_void),
+                                          data: *const libc::c_void) {
+    unsafe {
+        let pbag = &*pbag;
+
+        pbag.enumerate(enum_fn, data);
+    }
+}
+
+#[no_mangle]
+pub extern fn rsvg_property_bag_lookup(pbag: *const PropertyBag,
+                                       raw_key: *const libc::c_char) -> *const libc::c_char {
+    unsafe {
+        let pbag = &*pbag;
+        let key = CStr::from_ptr(raw_key);
+        match pbag.lookup_cstr(key) {
+            Some(v) => v.as_ptr(),
+            None => ptr::null()
         }
     }
 }
@@ -102,3 +174,39 @@ pub fn parse_or_value<T> (pbag: &PropertyBag,
 {
     Ok (parse_or_none (pbag, key, data, validate)?.unwrap_or (value))
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::ffi::CString;
+
+    #[test]
+    fn empty_property_bag() {
+        let map = unsafe { PropertyBag::new_from_key_value_pairs(ptr::null()) };
+        assert_eq!(map.len(), 0);
+    }
+
+    #[test]
+    fn property_bag_lookups() {
+        let pairs = [
+            CString::new("alpha").unwrap(),
+            CString::new("1").unwrap(),
+            CString::new("beta").unwrap(),
+            CString::new("2").unwrap(),
+        ];
+
+        let mut v = Vec::new();
+
+        for x in &pairs {
+            v.push(x.as_ptr() as *const libc::c_char);
+        }
+
+        v.push(ptr::null());
+
+        let map = unsafe { PropertyBag::new_from_key_value_pairs(v.as_ptr()) };
+
+        assert_eq!(map.lookup("alpha"), Some("1"));
+        assert_eq!(map.lookup("beta"), Some("2"));
+        assert_eq!(map.lookup("gamma"), None);
+    }
+}
diff --git a/rust/src/stop.rs b/rust/src/stop.rs
index 7e29ede0..1091a643 100644
--- a/rust/src/stop.rs
+++ b/rust/src/stop.rs
@@ -12,7 +12,7 @@ use handle::RsvgHandle;
 use length::*;
 use node::*;
 use opacity::*;
-use property_bag::{self, FfiRsvgPropertyBag, PropertyBag};
+use property_bag::{self, PropertyBag};
 use state::RsvgState;
 
 pub struct NodeStop {
@@ -172,7 +172,7 @@ fn u32_from_rgba (rgba: cssparser::RGBA) -> u32 {
 }
 
 extern "C" {
-    fn rsvg_parse_presentation_attributes (state: *mut RsvgState, pbag: FfiRsvgPropertyBag);
+    fn rsvg_parse_presentation_attributes (state: *mut RsvgState, pbag: *const PropertyBag);
     fn rsvg_parse_style (state: *mut RsvgState, string: *const libc::c_char);
 }
 
diff --git a/rust/src/structure.rs b/rust/src/structure.rs
index 841b6170..bceb8833 100644
--- a/rust/src/structure.rs
+++ b/rust/src/structure.rs
@@ -13,7 +13,7 @@ use handle::RsvgHandle;
 use length::*;
 use node::*;
 use parsers::Parse;
-use property_bag::{self, FfiRsvgPropertyBag, PropertyBag};
+use property_bag::{self, OwnedPropertyBag, PropertyBag};
 use util::*;
 use viewbox::*;
 use viewport::{ClipMode,draw_in_viewport};
@@ -117,7 +117,7 @@ struct NodeSvg {
     w:                     Cell<RsvgLength>,
     h:                     Cell<RsvgLength>,
     vbox:                  Cell<Option<ViewBox>>,
-    atts:                  RefCell<Option<PropertyBag>>
+    pbag:                  RefCell<Option<OwnedPropertyBag>>
 }
 
 impl NodeSvg {
@@ -129,7 +129,7 @@ impl NodeSvg {
             w:                     Cell::new (RsvgLength::parse ("100%", LengthDir::Horizontal).unwrap ()),
             h:                     Cell::new (RsvgLength::parse ("100%", LengthDir::Vertical).unwrap ()),
             vbox:                  Cell::new (None),
-            atts:                  RefCell::new(None)
+            pbag:                  RefCell::new(None)
         }
     }
 }
@@ -161,7 +161,7 @@ impl NodeTrait for NodeSvg {
 
         // The "style" sub-element is not loaded yet here, so we need
         // to store other attributes to be applied later.
-        *self.atts.borrow_mut() = Some(pbag.dup());
+        *self.pbag.borrow_mut() = Some(pbag.to_owned());
 
         Ok (())
     }
@@ -432,7 +432,7 @@ extern "C" {
                                tag:    *const libc::c_char,
                                class:  *const libc::c_char,
                                id:     *const libc::c_char,
-                               pbag:   FfiRsvgPropertyBag);
+                               pbag:   *const PropertyBag);
 }
 
 #[no_mangle]
@@ -441,7 +441,9 @@ pub extern fn rsvg_node_svg_apply_atts (raw_node: *const RsvgNode, handle: *cons
     let node: &RsvgNode = unsafe { & *raw_node };
 
     node.with_impl (|svg: &NodeSvg| {
-        if let Some(pbag) = svg.atts.borrow().as_ref() {
+        if let Some(owned_pbag) = svg.pbag.borrow().as_ref() {
+            let pbag = PropertyBag::from_owned(&owned_pbag);
+
             let class = pbag.lookup("class");
             let id = pbag.lookup("id");
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]