[librsvg] node.rs: Implement rsvg_node_ref() and rsvg_node_unref()
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] node.rs: Implement rsvg_node_ref() and rsvg_node_unref()
- Date: Fri, 17 Feb 2017 16:39:19 +0000 (UTC)
commit 2477434b4c8ec179b372817d464104ba06f20b30
Author: Federico Mena Quintero <federico gnome org>
Date: Wed Feb 15 19:44:40 2017 -0600
node.rs: Implement rsvg_node_ref() and rsvg_node_unref()
In Rust, we have Rc<Node> for the main refcounted node struct.
We export that to C by boxing as Box<Rc<Node>>, since an Rc<Node>
normally lives in the stack - that is, the Rc is in the stack, and the
Node and its refcount are in the heap.
When we ref() a node, we return a new Box:
Box::into_raw (Box::new (node.clone ()))
This means that in C, "x = rsvg_node_ref (y)" gives you back a pointer x
that is different from y! Both refer to the same Node in the Rust
world, and after that the node has one more refcount, as expected.
When we unref() a node, we expect you to call "x = rsvg_node_unref (x)".
This returns NULL, so your x=NULL after that, i.e. the node that was in
x is not accessible anymore.
rsvg-base.c | 2 +-
rsvg-private.h | 15 ++++++++---
rust/src/cnode.rs | 8 +++---
rust/src/lib.rs | 1 +
rust/src/node.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++---
5 files changed, 84 insertions(+), 13 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index 3397a42..449d8de 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -426,7 +426,7 @@ rsvg_standard_element_start (RsvgHandle * ctx, const char *name, RsvgPropertyBag
ctx->priv->treebase = newnode;
}
- ctx->priv->currentnode = newnode;
+ ctx->priv->currentnode = rsvg_node_ref (newnode);
node_set_atts (newnode, ctx, creator, atts);
}
diff --git a/rsvg-private.h b/rsvg-private.h
index be830db..1d24f2f 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -339,6 +339,7 @@ typedef void (* CNodeDraw) (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx,
typedef void (* CNodeFree) (gpointer impl);
/* Implemented in rust/src/node.rs */
+/* Call node = rsvg_node_unref (node) when you are done with the node */
G_GNUC_INTERNAL
RsvgNode *rsvg_rust_cnode_new (RsvgNodeType node_type,
RsvgNode *parent,
@@ -346,7 +347,7 @@ RsvgNode *rsvg_rust_cnode_new (RsvgNodeType node_type,
gpointer impl,
CNodeSetAtts set_atts_fn,
CNodeDraw draw_fn,
- CNodeFree free_fn);
+ CNodeFree free_fn) G_GNUC_WARN_UNUSED_RESULT;
/* Implemented in rust/src/node.rs */
G_GNUC_INTERNAL
@@ -357,8 +358,14 @@ G_GNUC_INTERNAL
RsvgNodeType rsvg_node_get_type (RsvgNode *node);
/* Implemented in rust/src/node.rs */
+/* Call this as newref = rsvg_node_ref (node); You don't own the node anymore, just the newref! */
G_GNUC_INTERNAL
-void rsvg_node_unref (RsvgNode *node);
+RsvgNode *rsvg_node_ref (RsvgNode *node) G_GNUC_WARN_UNUSED_RESULT;
+
+/* Implemented in rust/src/node.rs */
+/* Call this as node = rsvg_node_unref (node); Then node will be NULL and you don't own it anymore! */
+G_GNUC_INTERNAL
+RsvgNode *rsvg_node_unref (RsvgNode *node) G_GNUC_WARN_UNUSED_RESULT;
/* Implemented in rust/src/node.rs */
G_GNUC_INTERNAL
@@ -366,11 +373,11 @@ RsvgState *rsvg_node_get_state (RsvgNode *node);
/* Implemented in rust/src/node.rs
*
- * Returns a strong reference to the parent (or NULL); use rsvg_node_unref()
+ * Returns a new strong reference to the parent (or NULL); use rsvg_node_unref()
* when you are done.
*/
G_GNUC_INTERNAL
-RsvgNode *rsvg_node_get_parent (RsvgNode *node);
+RsvgNode *rsvg_node_get_parent (RsvgNode *node) G_GNUC_WARN_UNUSED_RESULT;
/* Implemented in rust/src/node.rs */
G_GNUC_INTERNAL
diff --git a/rust/src/cnode.rs b/rust/src/cnode.rs
index 2ad4a69..d97367f 100644
--- a/rust/src/cnode.rs
+++ b/rust/src/cnode.rs
@@ -64,10 +64,10 @@ pub extern fn rsvg_rust_cnode_new (node_type: NodeType,
free_fn: free_fn
};
- Box::into_raw (Box::new (Rc::new (Node::new (node_type,
- parent,
- state,
- Box::new (cnode)))))
+ box_node (Rc::new (Node::new (node_type,
+ parent,
+ state,
+ Box::new (cnode))))
}
#[no_mangle]
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 7ea6920..a3cea12 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -57,6 +57,7 @@ pub use length::{
pub use node::{
rsvg_node_get_type,
rsvg_node_get_parent,
+ rsvg_node_ref,
rsvg_node_unref,
rsvg_node_get_state,
rsvg_node_add_child,
diff --git a/rust/src/node.rs b/rust/src/node.rs
index 8946ef0..5ede878 100644
--- a/rust/src/node.rs
+++ b/rust/src/node.rs
@@ -4,6 +4,7 @@ use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;
use std::ptr;
+use std::mem;
use drawing_ctx::RsvgDrawingCtx;
@@ -140,7 +141,7 @@ extern "C" {
impl Drop for Node {
fn drop (&mut self) {
- unsafe { rsvg_state_free (self.state); }
+// unsafe { rsvg_state_free (self.state); }
}
}
@@ -152,6 +153,10 @@ pub extern fn rsvg_node_get_type (raw_node: *const RsvgNode) -> NodeType {
node.get_type ()
}
+pub fn box_node (node: RsvgNode) -> *mut RsvgNode {
+ Box::into_raw (Box::new (node))
+}
+
#[no_mangle]
pub extern fn rsvg_node_get_parent (raw_node: *const RsvgNode) -> *const RsvgNode {
assert! (!raw_node.is_null ());
@@ -162,16 +167,26 @@ pub extern fn rsvg_node_get_parent (raw_node: *const RsvgNode) -> *const RsvgNod
Some (ref weak_node) => {
let strong_node = weak_node.upgrade ().unwrap ();
- Box::into_raw (Box::new (strong_node))
+ box_node (strong_node)
}
}
}
#[no_mangle]
-pub unsafe extern fn rsvg_node_unref (raw_node: *mut RsvgNode) {
+pub unsafe extern fn rsvg_node_ref (raw_node: *mut RsvgNode) -> *mut RsvgNode {
assert! (!raw_node.is_null ());
+ let node: &RsvgNode = & *raw_node;
- let _ = Box::from_raw (raw_node);
+ box_node (node.clone ())
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_unref (raw_node: *mut RsvgNode) -> *mut RsvgNode {
+ if !raw_node.is_null () {
+ let _ = unsafe { Box::from_raw (raw_node) };
+ }
+
+ ptr::null_mut () // so the caller can do "node = rsvg_node_unref (node);" and lose access to the node
}
#[no_mangle]
@@ -223,3 +238,51 @@ pub extern fn rsvg_node_foreach_child (raw_node: *const RsvgNode, func: NodeFore
}
}
}
+
+#[cfg(test)]
+mod tests {
+ use std::rc::Rc;
+ use drawing_ctx::RsvgDrawingCtx;
+ use handle::RsvgHandle;
+ use property_bag::RsvgPropertyBag;
+ use state::RsvgState;
+ use super::*;
+ use std::ptr;
+ use std::mem;
+
+ struct TestNodeImpl {}
+
+ impl NodeTrait for TestNodeImpl {
+ fn set_atts (&self, node: &RsvgNode, handle: *const RsvgHandle, pbag: *const RsvgPropertyBag) {
+ }
+
+ fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
+ }
+
+ fn get_c_impl (&self) -> *const RsvgCNodeImpl {
+ return ptr::null ();
+ }
+ }
+
+ #[test]
+ fn node_refs_and_unrefs () {
+ let node = Rc::new (Node::new (NodeType::Path,
+ None,
+ ptr::null_mut (),
+ Box::new (TestNodeImpl {})));
+
+ let mut ref1 = box_node (node);
+
+ let new_node: &mut RsvgNode = unsafe { &mut *ref1 };
+ let weak = Rc::downgrade (new_node);
+
+ let mut ref2 = unsafe { rsvg_node_ref (new_node) };
+ assert! (weak.upgrade ().is_some ());
+
+ ref2 = unsafe { rsvg_node_unref (ref2) };
+ assert! (weak.upgrade ().is_some ());
+
+ ref1 = unsafe { rsvg_node_unref (ref1) };
+ assert! (weak.upgrade ().is_none ());
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]