[librsvg: 5/7] Move rsvg_css_parse_number_list() completely to Rust. Yay!



commit dc4756378535d5db3b9c0a07deb607b0f71bcd70
Author: Federico Mena Quintero <federico gnome org>
Date:   Tue Jun 20 11:02:08 2017 -0500

    Move rsvg_css_parse_number_list() completely to Rust.  Yay!
    
    Unfortunately there is no to_glib_full() for arrays of doubles.  We call
    g_malloc_n() by hand to create an array that C can consume, and fill it
    with the values that we parsed.

 rsvg-css.c          |   38 -----------------------------
 rsvg-css.h          |    3 +-
 rust/src/lib.rs     |    1 +
 rust/src/parsers.rs |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 67 insertions(+), 40 deletions(-)
---
diff --git a/rsvg-css.c b/rsvg-css.c
index a75bfa7..6ca0656 100644
--- a/rsvg-css.c
+++ b/rsvg-css.c
@@ -319,44 +319,6 @@ rsvg_css_parse_list (const char *in_str, guint * out_list_len)
 }
 
 gboolean
-rsvg_css_parse_number_list (const char       *in_str,
-                            NumberListLength nlength,
-                            gsize            size,
-                            gdouble          **out_list,
-                            gsize            *out_list_len)
-{
-    gchar **string_array;
-    gdouble *output;
-    guint len, i;
-
-    *out_list = NULL;
-    *out_list_len = 0;
-
-    string_array = rsvg_css_parse_list (in_str, &len);
-
-    if (!(string_array && len))
-        return FALSE;
-
-    if ((nlength == NUMBER_LIST_LENGTH_EXACT && (gsize) len != size)
-        || (nlength == NUMBER_LIST_LENGTH_MAXIMUM && (gsize) len > size))
-        return FALSE;
-
-    output = g_new0 (gdouble, len);
-
-    /* TODO: some error checking */
-    for (i = 0; i < len; i++)
-        output[i] = g_ascii_strtod (string_array[i], NULL);
-
-    g_strfreev (string_array);
-
-    *out_list_len = len;
-
-    *out_list = output;
-
-    return TRUE;
-}
-
-gboolean
 rsvg_css_parse_overflow (const char *str, gboolean * inherit)
 {
     SETINHERIT ();
diff --git a/rsvg-css.h b/rsvg-css.h
index 4efbde6..74c3220 100644
--- a/rsvg-css.h
+++ b/rsvg-css.h
@@ -140,11 +140,12 @@ typedef enum {
     NUMBER_LIST_LENGTH_MAXIMUM
 } NumberListLength;
 
+/* Implemented in rust/src/parsers.rs */
 G_GNUC_INTERNAL
 gboolean rsvg_css_parse_number_list (const char      *in_str,
                                      NumberListLength nlength,
                                      gsize            size,
-                                     gdouble         **out_list,
+                                     gdouble        **out_list,
                                      gsize           *out_list_len);
 
 G_GNUC_INTERNAL
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 1323d1e..fe7f2a0 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -79,6 +79,7 @@ pub use opacity::{
 };
 
 pub use parsers::{
+    rsvg_css_parse_number_list,
     rsvg_css_parse_number_optional_number
 };
 
diff --git a/rust/src/parsers.rs b/rust/src/parsers.rs
index 948f5c5..548936e 100644
--- a/rust/src/parsers.rs
+++ b/rust/src/parsers.rs
@@ -4,8 +4,11 @@ use ::glib::translate::*;
 use ::glib_sys;
 use ::nom::{IResult, double, is_alphabetic};
 
-use std::str;
 use std::f64::consts::*;
+use std::mem;
+use std::ptr;
+use std::slice;
+use std::str;
 
 // I don't know how to copy a nom::IError for long-term storage
 // (i.e. when it can no longer reference the &[u8]).  So, we explode a
@@ -245,6 +248,66 @@ fn number_list (s: &str, length: ListLength) -> Result <Vec<f64>, NumberListErro
     Ok(v)
 }
 
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum NumberListLength {
+    Exact,
+    Maximum
+}
+
+#[no_mangle]
+pub extern fn rsvg_css_parse_number_list (in_str:   *const libc::c_char,
+                                          nlength:  NumberListLength,
+                                          size:     libc::size_t,
+                                          out_list: *mut *const libc::c_double,
+                                          out_list_length: *mut libc::size_t) -> glib_sys::gboolean {
+    assert! (!in_str.is_null ());
+    assert! (!out_list.is_null ());
+    assert! (!out_list_length.is_null ());
+
+    let length = match nlength {
+        NumberListLength::Exact   => ListLength::Exact (size),
+        NumberListLength::Maximum => ListLength::Maximum (size)
+    };
+
+    let s = unsafe { String::from_glib_none (in_str) };
+
+    let result = number_list (&s, length);
+
+    match result {
+        Ok (number_list) => {
+            let num_elems = number_list.len ();
+
+            let c_array = unsafe {
+                glib_sys::g_malloc_n (num_elems,
+                                      mem::size_of::<libc::c_double> ())
+                    as *mut libc::c_double
+            };
+
+            let mut array = unsafe { slice::from_raw_parts_mut (c_array, num_elems) };
+
+            for (i, v) in number_list.into_iter ().enumerate () {
+                array[i] = v;
+            }
+
+            unsafe {
+                *out_list = c_array;
+                *out_list_length = num_elems;
+            }
+
+            true
+        },
+
+        Err (_) => {
+            unsafe {
+                *out_list = ptr::null ();
+                *out_list_length = 0;
+            }
+            false
+        }
+    }.to_glib ()
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;


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