[niepce] fwk+rust: PropertyValue and PropertyBag are in Rust



commit d67cba3ac4fd0bc62334c82e66b9bce78aeb60f9
Author: Hubert Figuière <hub figuiere net>
Date:   Sun Sep 24 01:21:48 2017 -0400

    fwk+rust: PropertyValue and PropertyBag are in Rust
    
    - added cbindgen to generate C++ header

 Cargo.toml                               |    4 +-
 build.rs                                 |   27 +---
 src/capi.rs                              |   27 ++++
 src/engine/db/bindings.hpp               |    2 -
 src/engine/db/keyword.hpp                |    6 +
 src/engine/db/label.hpp                  |    5 +
 src/engine/db/libfolder.hpp              |    9 +-
 src/engine/db/libfolder.rs               |   34 ++--
 src/engine/db/libmetadata.cpp            |   51 ++++---
 src/engine/db/libmetadata.hpp            |    8 +-
 src/engine/db/libmetadata.rs             |   79 ++++------
 src/engine/db/library.rs                 |   94 +++++-------
 src/engine/db/mod.rs                     |    9 +-
 src/engine/db/properties-def.hpp         |    2 +-
 src/engine/db/properties.hpp             |    1 +
 src/engine/library/clienttypes.hpp       |    5 -
 src/engine/library/commands.rs           |    8 +-
 src/engine/library/notification.cpp      |    2 +-
 src/engine/library/notification.hpp      |   64 ++-------
 src/engine/library/notification.rs       |  239 ++++++++++++++++-------------
 src/fwk/base/date.hpp                    |    6 +
 src/fwk/base/date.rs                     |   12 +-
 src/fwk/base/mod.rs                      |    2 +
 src/fwk/base/propertybag.cpp             |   97 ++++++-------
 src/fwk/base/propertybag.hpp             |  137 +++++-------------
 src/fwk/base/propertybag.rs              |  119 +++++++++++++++
 src/fwk/base/propertyvalue.rs            |  160 ++++++++++++++++++++
 src/fwk/mod.rs                           |    3 +-
 src/fwk/toolkit/metadatawidget.cpp       |  106 +++++++------
 src/fwk/toolkit/metadatawidget.hpp       |    8 +-
 src/fwk/utils/exempi.hpp                 |    4 +
 src/lib.rs                               |    9 +-
 src/libraryclient/clientimpl.cpp         |    4 +-
 src/libraryclient/clientimpl.hpp         |    2 +-
 src/libraryclient/libraryclient.cpp      |    4 +-
 src/libraryclient/libraryclient.hpp      |    3 +-
 src/niepce/modules/map/mapmodule.cpp     |   22 ++--
 src/niepce/ui/gridviewmodule.cpp         |    5 +-
 src/niepce/ui/gridviewmodule.hpp         |    2 +-
 src/niepce/ui/imageliststore.cpp         |   11 +-
 src/niepce/ui/metadatapanecontroller.cpp |   12 +-
 src/niepce/ui/metadatapanecontroller.hpp |    8 +-
 src/niepce/ui/niepcewindow.cpp           |    2 +-
 src/niepce/ui/selectioncontroller.cpp    |   32 ++--
 src/niepce/ui/selectioncontroller.hpp    |    8 +-
 src/niepce/ui/workspacecontroller.cpp    |    4 +-
 src/rust_bindings.hpp                    |   50 ++++++
 47 files changed, 895 insertions(+), 613 deletions(-)
---
diff --git a/Cargo.toml b/Cargo.toml
index 2ec1d30..f1c642f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,11 +2,12 @@
 name = "niepce_rust"
 version = "0.1.0"
 authors = ["Hubert Figuière <hub figuiere net>"]
+build = "build.rs"
 
 [dependencies]
 libc = "0.2.23"
 rusqlite = { version = "0.12.0", features = ["functions"] }
-exempi = "2.4.4"
+exempi = { version = "2.4.4", git = "https://github.com/hfiguiere/exempi-rs.git"; }
 glib-sys = "0.4.0"
 gio-sys = "0.4.0"
 gio = "0.2.0"
@@ -14,6 +15,7 @@ gio = "0.2.0"
 
 [build-dependencies]
 bindgen = "0.30.0"
+cbindgen = "0.1.23"
 pkg-config = "0.3.9"
 
 [lib]
diff --git a/build.rs b/build.rs
index 6bd2964..b182deb 100644
--- a/build.rs
+++ b/build.rs
@@ -1,4 +1,5 @@
 extern crate bindgen;
+extern crate cbindgen;
 extern crate pkg_config;
 
 use std::env;
@@ -20,30 +21,10 @@ fn main() {
         // bindings for.
         .whitelisted_type("eng::NiepceProperties")
         .whitelisted_type("eng::LibFileType")
-        .whitelisted_type("eng::LibNotificationType")
-        .whitelisted_type("eng::LnFileMove")
-        .whitelisted_type("eng::LnFolderCount")
         .whitelisted_type("eng::QueriedContent")
         .opaque_type("eng::QueriedContent")
-        .whitelisted_type("eng::metadata_desc_t")
         .whitelisted_type("eng::LibraryManaged")
         .whitelisted_type("fwk::FileList")
-        // PropertyValue is complicated
-        .whitelisted_type("fwk::PropertyValue")
-        .opaque_type("fwk::PropertyValue")
-        .whitelisted_type("fwk::StringArray")
-        .opaque_type("fwk::StringArray")
-        .whitelisted_function("fwk::is_empty")
-        .whitelisted_function("fwk::is_integer")
-        .whitelisted_function("fwk::is_string")
-        .whitelisted_function("fwk::is_string_array")
-        .whitelisted_function("fwk::is_date")
-        .whitelisted_function("fwk::get_integer")
-        .whitelisted_function("fwk::get_date")
-        .whitelisted_function("fwk::get_string_cstr")
-        .whitelisted_function("fwk::get_string_array")
-        .whitelisted_function("fwk::string_array_len")
-        .whitelisted_function("fwk::string_array_at_cstr")
         .whitelisted_type("eng::IndexToXmp")
         .whitelisted_function("eng::property_index_to_xmp")
         .header("src/engine/db/bindings.hpp")
@@ -67,4 +48,10 @@ fn main() {
     bindings
         .write_to_file(out_path.join("bindings.rs"))
         .expect("Couldn't write bindings!");
+
+    // Use cbindgen to generate C bindings.
+    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
+    cbindgen::generate(&crate_dir)
+        .unwrap()
+        .write_to_file("target/bindings.h");
 }
diff --git a/src/capi.rs b/src/capi.rs
new file mode 100644
index 0000000..54d85ab
--- /dev/null
+++ b/src/capi.rs
@@ -0,0 +1,27 @@
+/*
+ * niepce - capi.rs
+ *
+ * Copyright (C) 2017 Hubert Figuière
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+use libc::c_char;
+use std::ffi::CString;
+
+/// Release the raw pointer from a CString.
+#[no_mangle]
+pub extern "C" fn rust_cstring_delete(string: *mut c_char) {
+    unsafe { CString::from_raw(string); }
+}
diff --git a/src/engine/db/bindings.hpp b/src/engine/db/bindings.hpp
index d1db23f..66afae8 100644
--- a/src/engine/db/bindings.hpp
+++ b/src/engine/db/bindings.hpp
@@ -4,7 +4,5 @@
 
 #include "engine/db/libmetadata.hpp"
 #include "engine/db/library.hpp"
-#include "engine/library/clienttypes.hpp"
 #include "engine/library/notification.hpp"
-#include "fwk/base/propertybag.hpp"
 #include "fwk/utils/files.hpp"
diff --git a/src/engine/db/keyword.hpp b/src/engine/db/keyword.hpp
index 4821631..e077376 100644
--- a/src/engine/db/keyword.hpp
+++ b/src/engine/db/keyword.hpp
@@ -25,9 +25,15 @@
 
 #include "engine/db/librarytypes.hpp"
 
+#include "rust_bindings.hpp"
+
 // just a rust interface.
 namespace eng {
+
+#if RUST_BINDGEN
 class Keyword;
+#endif
+
 typedef std::shared_ptr<Keyword> KeywordPtr;
 typedef std::vector<KeywordPtr> KeywordList;
 typedef std::shared_ptr<KeywordList> KeywordListPtr;
diff --git a/src/engine/db/label.hpp b/src/engine/db/label.hpp
index ddbfac2..9d73056 100644
--- a/src/engine/db/label.hpp
+++ b/src/engine/db/label.hpp
@@ -25,13 +25,18 @@
 
 #include "engine/db/librarytypes.hpp"
 
+#include "rust_bindings.hpp"
+
 namespace fwk {
 class RgbColour;
 }
 
 namespace eng {
 
+
+#if RUST_BINDGEN
 class Label;
+#endif
 typedef std::shared_ptr<Label> LabelPtr;
 typedef std::vector<LabelPtr> LabelList;
 typedef std::shared_ptr<LabelList> LabelListPtr;
diff --git a/src/engine/db/libfolder.hpp b/src/engine/db/libfolder.hpp
index 1e2a4ec..7fbfa70 100644
--- a/src/engine/db/libfolder.hpp
+++ b/src/engine/db/libfolder.hpp
@@ -25,8 +25,14 @@
 
 #include "engine/db/librarytypes.hpp"
 
+#include "rust_bindings.hpp"
+
 namespace eng {
+
+#if RUST_BINDGEN
 class LibFolder;
+#endif
+
 typedef std::shared_ptr<LibFolder> LibFolderPtr;
 typedef std::list<LibFolderPtr> LibFolderList;
 typedef std::shared_ptr<LibFolderList> LibFolderListPtr;
@@ -42,9 +48,6 @@ LibFolderPtr libfolder_new(library_id_t id, const char *name);
 
 extern "C" {
 library_id_t engine_db_libfolder_id(const LibFolder *);
-const char *engine_db_libfolder_name(const LibFolder *);
-int32_t engine_db_libfolder_virtual_type(const LibFolder *);
-bool engine_db_libfolder_expanded(const LibFolder *);
 void engine_db_libfolder_set_locked(const LibFolder *, bool);
 void engine_db_libfolder_set_expanded(const LibFolder *, bool);
 void engine_db_libfolder_set_virtual_type(const LibFolder *, int32_t);
diff --git a/src/engine/db/libfolder.rs b/src/engine/db/libfolder.rs
index d87b7ae..27c797c 100644
--- a/src/engine/db/libfolder.rs
+++ b/src/engine/db/libfolder.rs
@@ -122,48 +122,48 @@ impl FromDb for LibFolder {
 }
 
 #[no_mangle]
-pub extern fn engine_db_libfolder_new(id: i64, name: *const c_char) -> *mut LibFolder {
+pub extern "C" fn engine_db_libfolder_new(id: i64, name: *const c_char) -> *mut LibFolder {
     let lf = Box::new(LibFolder::new(id, &*unsafe { CStr::from_ptr(name) }.to_string_lossy()));
     Box::into_raw(lf)
 }
 
 #[no_mangle]
-pub extern fn engine_db_libfolder_delete(lf: *mut LibFolder) {
+pub extern "C" fn engine_db_libfolder_delete(lf: *mut LibFolder) {
     unsafe { Box::from_raw(lf) };
 }
 
 #[no_mangle]
-pub extern fn engine_db_libfolder_id(this: &LibFolder) -> i64 {
-    this.id() as i64
+pub extern "C" fn engine_db_libfolder_id(obj: &LibFolder) -> i64 {
+    obj.id() as i64
 }
 
 #[no_mangle]
-pub extern fn engine_db_libfolder_name(this: &mut LibFolder) -> *const c_char {
-    this.cstr = CString::new(this.name().clone()).unwrap();
-    this.cstr.as_ptr()
+pub extern "C" fn engine_db_libfolder_name(obj: &mut LibFolder) -> *const c_char {
+    obj.cstr = CString::new(obj.name().clone()).unwrap();
+    obj.cstr.as_ptr()
 }
 
 #[no_mangle]
-pub extern fn engine_db_libfolder_virtual_type(this: &LibFolder) -> i32 {
-    this.virtual_type() as i32
+pub extern "C" fn engine_db_libfolder_virtual_type(obj: &LibFolder) -> i32 {
+    obj.virtual_type() as i32
 }
 
 #[no_mangle]
-pub extern fn engine_db_libfolder_expanded(this: &LibFolder) -> bool {
-    this.expanded
+pub extern "C" fn engine_db_libfolder_expanded(obj: &LibFolder) -> bool {
+    obj.expanded
 }
 
 #[no_mangle]
-pub extern fn engine_db_libfolder_set_locked(this: &mut LibFolder, locked: bool) {
-    this.set_locked(locked);
+pub extern fn engine_db_libfolder_set_locked(obj: &mut LibFolder, locked: bool) {
+    obj.set_locked(locked);
 }
 
 #[no_mangle]
-pub extern fn engine_db_libfolder_set_expanded(this: &mut LibFolder, expanded: bool) {
-    this.set_expanded(expanded);
+pub extern fn engine_db_libfolder_set_expanded(obj: &mut LibFolder, expanded: bool) {
+    obj.set_expanded(expanded);
 }
 
 #[no_mangle]
-pub extern fn engine_db_libfolder_set_virtual_type(this: &mut LibFolder, t: i32) {
-    this.set_virtual_type(VirtualType::from(t));
+pub extern fn engine_db_libfolder_set_virtual_type(obj: &mut LibFolder, t: i32) {
+    obj.set_virtual_type(VirtualType::from(t));
 }
diff --git a/src/engine/db/libmetadata.cpp b/src/engine/db/libmetadata.cpp
index 0dedae8..681cec4 100644
--- a/src/engine/db/libmetadata.cpp
+++ b/src/engine/db/libmetadata.cpp
@@ -17,11 +17,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <exempi/xmpconsts.h>
-#include <exempi/xmperrors.h>
 #include <string.h>
 #include <time.h>
 
+#include <algorithm>
+#include <map>
+
+#include <exempi/xmpconsts.h>
+#include <exempi/xmperrors.h>
+
 #include "fwk/base/date.hpp"
 #include "fwk/base/debug.hpp"
 #include "fwk/base/rust.hpp"
@@ -67,7 +71,7 @@ IndexToXmp property_index_to_xmp(fwk::PropertyIndex index)
 }
 
 bool get_meta_data(const LibMetadata *meta, fwk::PropertyIndex p,
-                   fwk::PropertyValue &value)
+                   fwk::PropertyValuePtr &value)
 {
     const PropsToXmpMap &propmap = props_to_xmp_map();
     PropsToXmpMap::const_iterator iter = propmap.find(p);
@@ -94,7 +98,7 @@ bool get_meta_data(const LibMetadata *meta, fwk::PropertyIndex p,
         const char *v = NULL;
         v = xmp_string_cstr(xmp_value);
         if (v) {
-            value = fwk::PropertyValue(v);
+            value = fwk::property_value_new(v);
             return true;
         }
     }
@@ -104,62 +108,67 @@ bool get_meta_data(const LibMetadata *meta, fwk::PropertyIndex p,
 
 void libmetadata_to_properties(const LibMetadata *meta,
                                const fwk::PropertySet &propset,
-                               fwk::PropertyBag &props)
+                               fwk::PropertyBagPtr &props)
 {
+    if (!props) {
+        props = fwk::property_bag_new();
+    }
     std::for_each(
         propset.begin(), propset.end(),
         [&props, meta](fwk::PropertySet::key_type prop_id) {
             auto xmpmeta = engine_libmetadata_get_xmpmeta(meta);
             switch (prop_id) {
             case NpXmpRatingProp:
-                props.set_value_for_property(
-                    prop_id,
-                    fwk::PropertyValue(fwk_xmp_meta_get_rating(xmpmeta)));
+                fwk::set_value_for_property(
+                    *props, prop_id,
+                    *fwk::property_value_new(fwk_xmp_meta_get_rating(xmpmeta)));
                 break;
             case NpXmpLabelProp: {
                 char *str = fwk_xmp_meta_get_label(xmpmeta);
                 if (str) {
-                    props.set_value_for_property(prop_id,
-                                                 fwk::PropertyValue(str));
+                    fwk::set_value_for_property(*props, prop_id,
+                                                *fwk::property_value_new(str));
                     rust_cstring_delete(str);
                 } else {
-                    props.set_value_for_property(prop_id,
-                                                 fwk::PropertyValue(""));
+                    fwk::set_value_for_property(*props, prop_id,
+                                                *fwk::property_value_new(""));
                 }
                 break;
             }
             case NpTiffOrientationProp:
-                props.set_value_for_property(
-                    prop_id,
-                    fwk::PropertyValue(fwk_xmp_meta_get_orientation(xmpmeta)));
+                fwk::set_value_for_property(
+                    *props, prop_id,
+                    *fwk::property_value_new(fwk_xmp_meta_get_orientation(xmpmeta)));
                 break;
             case NpExifDateTimeOriginalProp: {
                 fwk::DatePtr date =
                     fwk::date_wrap(fwk_xmp_meta_get_creation_date(xmpmeta));
-                props.set_value_for_property(prop_id, fwk::PropertyValue(date));
+                if (date) {
+                    fwk::set_value_for_property(*props, prop_id, *fwk::property_value_new(date));
+                }
                 break;
             }
             case NpIptcKeywordsProp: {
                 xmp::ScopedPtr<XmpIteratorPtr> iter(
                     xmp_iterator_new(engine_libmetadata_get_xmp(meta), NS_DC,
                                      "subject", XMP_ITER_JUSTLEAFNODES));
-                fwk::StringArray vec;
+                std::vector<std::string> vec;
                 xmp::ScopedPtr<XmpStringPtr> value(xmp_string_new());
                 while (xmp_iterator_next(iter, NULL, NULL, value, NULL)) {
                     vec.push_back(xmp_string_cstr(value));
                 }
-                fwk::PropertyValue v(vec);
+                fwk::PropertyValuePtr v = fwk::property_value_new(vec);
                 // DBG_ASSERT(check_property_type(prop_id, v.type()), "wrong
                 // type");
-                props.set_value_for_property(prop_id, v);
+                fwk::set_value_for_property(*props, prop_id, *v);
                 break;
             }
             default: {
-                fwk::PropertyValue propval;
+                fwk::PropertyValuePtr propval;
                 if (get_meta_data(meta, prop_id, propval)) {
                     // DBG_ASSERT(check_property_type(prop_id, propval.type()),
                     // "wrong type");
-                    props.set_value_for_property(prop_id, propval);
+                    fwk::set_value_for_property(*props, prop_id, *propval);
                 } else {
                     DBG_OUT("missing prop %u", prop_id);
                 }
diff --git a/src/engine/db/libmetadata.hpp b/src/engine/db/libmetadata.hpp
index 5fd15aa..fc32282 100644
--- a/src/engine/db/libmetadata.hpp
+++ b/src/engine/db/libmetadata.hpp
@@ -23,20 +23,22 @@
 #include <string>
 #include <vector>
 
-#include <boost/any.hpp>
-
 #include "engine/db/librarytypes.hpp"
 #include "engine/db/metadata.hpp"
 #include "fwk/base/propertybag.hpp"
 #include "fwk/utils/exempi.hpp"
 
+#include "rust_bindings.hpp"
+
 namespace eng {
 
+#if RUST_BINDGEN
 class LibMetadata;
+#endif
 
 void libmetadata_to_properties(const LibMetadata *meta,
                                const fwk::PropertySet &propset,
-                               fwk::PropertyBag &props);
+                               fwk::PropertyBagPtr &props);
 
 struct IndexToXmp {
     const char *ns;
diff --git a/src/engine/db/libmetadata.rs b/src/engine/db/libmetadata.rs
index cc42f41..846b6f0 100644
--- a/src/engine/db/libmetadata.rs
+++ b/src/engine/db/libmetadata.rs
@@ -23,6 +23,7 @@ use exempi;
 
 use fwk;
 use fwk::{
+    PropertyValue,
     XmpMeta,
     make_xmp_date_time
 };
@@ -32,20 +33,6 @@ use super::{
     LibraryId
 };
 use root::eng::NiepceProperties as Np;
-use root::fwk::{
-    is_empty,
-    is_integer,
-    is_string,
-    is_string_array,
-    is_date,
-    get_string_cstr,
-    get_string_array,
-    get_integer,
-    get_date,
-    string_array_len,
-    string_array_at_cstr,
-    PropertyValue
-};
 
 pub struct LibMetadata {
     xmp: XmpMeta,
@@ -92,44 +79,44 @@ impl LibMetadata {
 
     pub fn set_metadata(&mut self, meta: Np, value: &PropertyValue) -> bool {
         if let Some(ix) = property_index_to_xmp(meta) {
-            if unsafe { is_empty(value) } {
-                return self.xmp.xmp.delete_property(&ix.ns, &ix.property);
-            } else if unsafe { is_integer(value) } {
-                return self.xmp.xmp.set_property_i32(
-                    &ix.ns, &ix.property, unsafe { get_integer(value) }, exempi::PROP_NONE);
-            } else if unsafe { is_string(value) } {
-                let cstr = unsafe { CStr::from_ptr(get_string_cstr(value)) };
-                if cstr.to_bytes().len() == 0 {
-                    return self.xmp.xmp.delete_property(&ix.ns, &ix.property);
-                } else if !self.xmp.xmp.set_property(
-                    &ix.ns, &ix.property, &*cstr.to_string_lossy(), exempi::PROP_NONE) {
-                    if exempi::get_error() == exempi::Error::BadXPath {
-                        return self.xmp.xmp.set_localized_text(
-                            &ix.ns, &ix.property, "", "x-default",
-                            &*cstr.to_string_lossy(), exempi::PROP_NONE);
+            match value {
+                &PropertyValue::Empty =>
+                    return self.xmp.xmp.delete_property(&ix.ns, &ix.property),
+                &PropertyValue::Int(i) =>
+                    return self.xmp.xmp.set_property_i32(
+                        &ix.ns, &ix.property, i, exempi::PROP_NONE),
+                &PropertyValue::String(ref s) => {
+                    if s.is_empty() {
+                        return self.xmp.xmp.delete_property(&ix.ns, &ix.property);
+                    } else if !self.xmp.xmp.set_property(
+                        &ix.ns, &ix.property, s, exempi::PROP_NONE) {
+                        if exempi::get_error() == exempi::Error::BadXPath {
+                            return self.xmp.xmp.set_localized_text(
+                                &ix.ns, &ix.property, "", "x-default",
+                                s, exempi::PROP_NONE);
+                        }
+                    } else {
+                        return true;
+                    }
+                },
+                &PropertyValue::StringArray(ref sa) => {
+                    self.xmp.xmp.delete_property(&ix.ns, &ix.property);
+                    for i in 0..sa.len() {
+                        self.xmp.xmp.append_array_item(&ix.ns, &ix.property,
+                                                       exempi::PROP_VALUE_IS_ARRAY,
+                                                       &sa[i],
+                                                       exempi::PROP_NONE);
                     }
-                } else {
                     return true;
+                },
+                &PropertyValue::Date(ref d) => {
+                    return self.xmp.xmp.set_property_date(
+                        &ix.ns, &ix.property, d.xmp_date(), exempi::PROP_NONE);
                 }
-            } else if unsafe { is_string_array(value) } {
-                self.xmp.xmp.delete_property(&ix.ns, &ix.property);
-                let a = unsafe { get_string_array(value) };
-                let count = unsafe { string_array_len(a) };
-                for i in 0..count {
-                    let cstr = unsafe { CStr::from_ptr(string_array_at_cstr(a, i)) };
-                    self.xmp.xmp.append_array_item(&ix.ns, &ix.property,
-                                                   exempi::PROP_VALUE_IS_ARRAY,
-                                                   &*cstr.to_string_lossy(),
-                                                   exempi::PROP_NONE);
-                }
-                return true;
-            } else if unsafe { is_date(value) } {
-                let d = unsafe { get_date(value) } as *const fwk::Date;
-                return self.xmp.xmp.set_property_date(
-                    &ix.ns, &ix.property, unsafe { &(*d) }.xmp_date(), exempi::PROP_NONE);
             }
             err_out!("error setting property {}:{} {}", ix.ns, ix.property,
                      exempi::get_error() as u32);
+            return false;
         }
         err_out!("Unknown property {:?}", meta);
         false
diff --git a/src/engine/db/library.rs b/src/engine/db/library.rs
index d759d87..bd33344 100644
--- a/src/engine/db/library.rs
+++ b/src/engine/db/library.rs
@@ -17,10 +17,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-use libc::{
-    c_char,
-    c_void
-};
+use libc::c_char;
 use std::path::{
     Path,
     PathBuf
@@ -45,15 +42,7 @@ use engine::db::keyword::Keyword;
 use engine::library::notification::Notification as LibNotification;
 use engine::library::notification::engine_library_notify;
 use fwk;
-use root::fwk::{
-    PropertyValue,
-    is_empty,
-    is_integer,
-    get_integer,
-    get_string_array,
-    string_array_len,
-    string_array_at_cstr
-};
+use fwk::PropertyValue;
 use root::eng::NiepceProperties as Np;
 pub use root::eng::LibraryManaged as Managed;
 
@@ -201,11 +190,11 @@ impl Library {
     }
 
     pub fn notify(&self, notif: Box<LibNotification>) {
-        unsafe { engine_library_notify(self.notif_id, Box::into_raw(notif) as *mut c_void); }
+        unsafe { engine_library_notify(self.notif_id, Box::into_raw(notif)); }
     }
 
     pub fn notify_by_id(id: u64,  notif: Box<LibNotification>) {
-        unsafe { engine_library_notify(id, Box::into_raw(notif) as *mut c_void); }
+        unsafe { engine_library_notify(id, Box::into_raw(notif)); }
     }
 
     pub fn add_jpeg_file_to_bundle(&self, file_id: LibraryId, fsfile_id: LibraryId) -> bool {
@@ -602,51 +591,52 @@ impl Library {
             Np::NpXmpLabelProp |
             Np::NpTiffOrientationProp |
             Np::NpNiepceFlagProp => {
-                if unsafe { is_empty(value) || is_integer(value) } {
-                    // internal
-                    // make the column mapping more generic.
-                    let column = match meta {
-                        Np::NpXmpRatingProp =>
-                            "rating",
-                        Np::NpXmpLabelProp =>
-                            "orientation",
-                        Np::NpTiffOrientationProp =>
-                            "label",
-                        Np::NpNiepceFlagProp =>
-                            "flag",
-                        _ =>
-                            unreachable!()
-                    };
-                    if !column.is_empty() {
-                        retval = self.set_internal_metadata(file_id, column,
-                                                            unsafe { get_integer(value) });
-                        if !retval {
-                            err_out!("set_internal_metadata() failed");
-                            return false;
+                match *value {
+                    PropertyValue::Int(i) => {
+                        // internal
+                        // make the column mapping more generic.
+                        let column = match meta {
+                            Np::NpXmpRatingProp =>
+                                "rating",
+                            Np::NpXmpLabelProp =>
+                                "orientation",
+                            Np::NpTiffOrientationProp =>
+                                "label",
+                            Np::NpNiepceFlagProp =>
+                                "flag",
+                            _ =>
+                                unreachable!()
+                        };
+                        if !column.is_empty() {
+                            retval = self.set_internal_metadata(file_id, column, i);
+                            if !retval {
+                                err_out!("set_internal_metadata() failed");
+                                return false;
+                            }
                         }
-                    }
-                } else {
-                    err_out!("improper value type for {:?}", meta);
+                    },
+                    _ =>
+                        err_out!("improper value type for {:?}", meta),
                 }
             },
             Np::NpIptcKeywordsProp => {
                 self.unassign_all_keywords_for_file(file_id);
 
-                let keywords = unsafe { get_string_array(value) };
-                let length = unsafe { string_array_len(keywords) };
-                for i in 0..length {
-                    let s = unsafe { string_array_at_cstr(keywords, i) };
-                    let cstr = unsafe { CStr::from_ptr(s) }.to_string_lossy();
-                    let id = self.make_keyword(&cstr);
-                    if id != -1 {
-                        self.assign_keyword(id, file_id);
-                    }
+                match value {
+                    &PropertyValue::StringArray(ref keywords) =>
+                        for kw in keywords {
+                            let id = self.make_keyword(&kw);
+                            if id != -1 {
+                                self.assign_keyword(id, file_id);
+                            }
+                        },
+                    _ =>
+                        err_out!("improper value_type for {:?} : {:?}", meta, value),
                 }
-            }
-            _ => {
+            },
+            _ =>
                 // XXX TODO
-                dbg_out!("unhandled meta {}", meta as u32);
-            }
+                err_out!("unhandled meta {:?}", meta),
         }
         if let Some(mut metablock) = self.get_metadata(file_id) {
             metablock.set_metadata(meta, value);
diff --git a/src/engine/db/mod.rs b/src/engine/db/mod.rs
index 7b40054..927b303 100644
--- a/src/engine/db/mod.rs
+++ b/src/engine/db/mod.rs
@@ -1,5 +1,5 @@
 /*
- * niepce - eng/db/keyword.rs
+ * niepce - engine/db/mod.rs
  *
  * Copyright (C) 2017 Hubert Figuière
  *
@@ -28,6 +28,13 @@ pub mod library;
 
 pub type LibraryId = i64;
 
+// flatten namespace a bit.
+pub use self::label::Label;
+pub use self::libmetadata::LibMetadata;
+pub use self::libfolder::LibFolder;
+pub use self::keyword::Keyword;
+
+
 use rusqlite;
 
 pub trait FromDb {
diff --git a/src/engine/db/properties-def.hpp b/src/engine/db/properties-def.hpp
index 373c594..fdf0cbf 100644
--- a/src/engine/db/properties-def.hpp
+++ b/src/engine/db/properties-def.hpp
@@ -51,6 +51,6 @@ DEFINE_PROPERTY(NpExifGpsLatProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_GPSL
 
 DEFINE_PROPERTY(NpIptcHeadlineProp, MAKE_METADATA_IDX(META_NS_IPTC, META_IPTC_HEADLINE), NS_PHOTOSHOP, 
"Headline", std::string)
 DEFINE_PROPERTY(NpIptcDescriptionProp, MAKE_METADATA_IDX(META_NS_IPTC, META_IPTC_DESCRIPTION), NS_DC, 
"description", std::string)
-DEFINE_PROPERTY(NpIptcKeywordsProp, MAKE_METADATA_IDX(META_NS_IPTC, META_IPTC_KEYWORDS), NS_DC, "subject", 
fwk::StringArray)
+DEFINE_PROPERTY(NpIptcKeywordsProp, MAKE_METADATA_IDX(META_NS_IPTC, META_IPTC_KEYWORDS), NS_DC, "subject", 
std::vector<std::string>)
 
 DEFINE_PROPERTY(NpNiepceFlagProp, MAKE_METADATA_IDX(META_NS_NIEPCE, META_NIEPCE_FLAG), 
xmp::NIEPCE_XMP_NAMESPACE, "Flag", int32_t)
diff --git a/src/engine/db/properties.hpp b/src/engine/db/properties.hpp
index fe2244e..594b746 100644
--- a/src/engine/db/properties.hpp
+++ b/src/engine/db/properties.hpp
@@ -20,6 +20,7 @@
 
 #pragma once
 
+#include <map>
 #include <typeinfo>
 
 #include "fwk/base/propertybag.hpp"
diff --git a/src/engine/library/clienttypes.hpp b/src/engine/library/clienttypes.hpp
index 2f5b2a5..5f45375 100644
--- a/src/engine/library/clienttypes.hpp
+++ b/src/engine/library/clienttypes.hpp
@@ -27,11 +27,6 @@ namespace eng {
 
   typedef int tid_t; /**< transaction ID */
 
-  struct metadata_desc_t {
-    library_id_t id;
-    fwk::PropertyIndex          meta;
-    fwk::PropertyValue          value;
-  };
 }
 
 
diff --git a/src/engine/library/commands.rs b/src/engine/library/commands.rs
index 4b8d4c6..ab2f5e0 100644
--- a/src/engine/library/commands.rs
+++ b/src/engine/library/commands.rs
@@ -21,6 +21,7 @@ use libc::c_char;
 use std::ffi::CStr;
 use std::path::Path;
 
+use fwk::PropertyValue;
 use engine::db::LibraryId;
 use engine::db::library::{
     Library,
@@ -38,10 +39,7 @@ use super::notification::{
 };
 use root::eng::LibFile as CLibFile;
 use root::eng::NiepceProperties as Np;
-use root::fwk::{
-    FileList,
-    PropertyValue
-};
+use root::fwk::FileList;
 
 #[no_mangle]
 pub fn cmd_list_all_keywords(lib: &Library) -> bool {
@@ -149,7 +147,7 @@ pub fn cmd_set_metadata(lib: &Library, id: LibraryId, meta: Np,
                         value: &PropertyValue) -> bool {
     lib.set_metadata(id, meta, value);
     lib.notify(Box::new(LibNotification::MetadataChanged(
-        MetadataChange{id: id, meta: meta as u32, value: value.clone()})));
+        MetadataChange::new(id, meta as u32, Box::new(value.clone())))));
     true
 }
 
diff --git a/src/engine/library/notification.cpp b/src/engine/library/notification.cpp
index 5c13b14..1bc6731 100644
--- a/src/engine/library/notification.cpp
+++ b/src/engine/library/notification.cpp
@@ -32,7 +32,7 @@ namespace {
 eng::LibNotificationPtr
 engine_library_notification_wrap(eng::LibNotification* n)
 {
-    return eng::LibNotificationPtr(n, &engine_library_notification_delete);
+    return eng::LibNotificationPtr(n, &ffi::engine_library_notification_delete);
 }
 }
 
diff --git a/src/engine/library/notification.hpp b/src/engine/library/notification.hpp
index 256af83..4be3a1a 100644
--- a/src/engine/library/notification.hpp
+++ b/src/engine/library/notification.hpp
@@ -26,14 +26,22 @@
 #include "engine/db/librarytypes.hpp"
 #include "engine/library/clienttypes.hpp"
 
+#include "rust_bindings.hpp"
+
 namespace eng {
+
+#if RUST_BINDGEN
+class Keyword;
 class Label;
-class LibMetadata;
 class LibFolder;
-class Keyword;
-
+class LibMetadata;
 class LibNotification;
-typedef std::shared_ptr<LibNotification> LibNotificationPtr;
+#endif
+
+typedef std::shared_ptr<eng::LibNotification> LibNotificationPtr;
+class MetadataChange;
+class FolderCount;
+class FileMove;
 
 enum class LibNotificationType {
     NONE = 0,
@@ -55,17 +63,6 @@ enum class LibNotificationType {
     FILE_MOVED
 };
 
-struct LnFileMove {
-    library_id_t file;
-    library_id_t from;
-    library_id_t to;
-};
-
-struct LnFolderCount {
-    library_id_t folder;
-    int64_t count;
-};
-
 struct QueriedContent {
     library_id_t container;
     LibFileListPtr files;
@@ -73,42 +70,5 @@ struct QueriedContent {
     QueriedContent(library_id_t container);
     void push(LibFile*);
 };
-}
-
-extern "C" {
-
-eng::LibNotificationType
-engine_library_notification_type(const eng::LibNotification* n);
-
-// if METADATA_CHANGE return the inner id. otherwise directly attached id.
-eng::library_id_t
-engine_library_notification_get_id(const eng::LibNotification* n);
-
-const eng::Label*
-engine_library_notification_get_label(const eng::LibNotification* n);
-
-const eng::LnFileMove*
-engine_library_notification_get_filemoved(const eng::LibNotification* n);
-
-const eng::LibMetadata*
-engine_library_notification_get_libmetadata(const eng::LibNotification* n);
-
-const eng::LnFolderCount*
-engine_library_notification_get_folder_count(const eng::LibNotification* n);
-
-const eng::metadata_desc_t*
-engine_library_notification_get_metadatachange(const eng::LibNotification* n);
-
-const eng::LibFolder*
-engine_library_notification_get_libfolder(const eng::LibNotification* n);
-
-const eng::Keyword*
-engine_library_notification_get_keyword(const eng::LibNotification* n);
-
-const eng::QueriedContent*
-engine_library_notification_get_content(const eng::LibNotification* n);
-
-void engine_library_notification_delete(eng::LibNotification* n);
 
-void engine_library_notify(uint64_t notify_id, eng::LibNotification* n);
 }
diff --git a/src/engine/library/notification.rs b/src/engine/library/notification.rs
index f211497..cda394d 100644
--- a/src/engine/library/notification.rs
+++ b/src/engine/library/notification.rs
@@ -17,19 +17,72 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-use libc::c_void;
-use engine::db::LibraryId;
-use engine::db::label::Label;
-use engine::db::libfolder::LibFolder;
-use engine::db::libmetadata::LibMetadata;
-use engine::db::keyword::Keyword;
-
-use root::eng::LibNotificationType as NotificationType;
-pub use root::eng::LnFileMove as FileMove;
-pub use root::eng::LnFolderCount as FolderCount;
-pub use root::eng::QueriedContent as Content;
-pub use root::eng::metadata_desc_t as MetadataChange;
+use fwk::base::PropertyIndex;
+use fwk::PropertyValue;
+use engine::db::{
+    LibraryId,
+    Label, LibFolder, LibMetadata, Keyword
+};
+
+use root::eng::QueriedContent;
+
+pub type Content = QueriedContent;
+
+#[repr(C)]
+#[allow(non_camel_case_types)]
+pub enum NotificationType {
+    NONE = 0,
+    NEW_LIBRARY_CREATED = 1,
+    ADDED_FOLDER = 2,
+    ADDED_FILE = 3,
+    ADDED_FILES = 4,
+    ADDED_KEYWORD = 5,
+    ADDED_LABEL = 6,
+    FOLDER_CONTENT_QUERIED = 7,
+    KEYWORD_CONTENT_QUERIED = 8,
+    METADATA_QUERIED = 9,
+    METADATA_CHANGED = 10,
+    LABEL_CHANGED = 11,
+    LABEL_DELETED = 12,
+    XMP_NEEDS_UPDATE = 13,
+    FOLDER_COUNTED = 14,
+    FOLDER_COUNT_CHANGE = 15,
+    FILE_MOVED = 16,
+}
+
+#[repr(C)]
+pub struct FileMove {
+    pub file: LibraryId,
+    pub from: LibraryId,
+    pub to: LibraryId,
+}
+
+#[repr(C)]
+pub struct FolderCount {
+    pub folder: LibraryId,
+    pub count: i64,
+}
+
+#[repr(C)]
+pub struct MetadataChange {
+    id: LibraryId,
+    meta: PropertyIndex,
+    value: *mut PropertyValue,
+}
+
+impl MetadataChange {
+    pub fn new(id: LibraryId, meta: PropertyIndex, value: Box<PropertyValue>) -> Self {
+        MetadataChange {id: id, meta: meta, value: Box::into_raw(value)}
+    }
+}
+
+impl Drop for MetadataChange {
+    fn drop(&mut self) {
+        unsafe { Box::from_raw(self.value); }
+    }
+}
 
+#[repr(C)]
 pub enum Notification {
     AddedFile,
     AddedFiles,
@@ -52,148 +105,120 @@ pub enum Notification {
 #[cfg(not(test))]
 extern "C" {
     // actually a *mut Notification
-    pub fn engine_library_notify(notif_id: u64, n: *mut c_void);
+    pub fn engine_library_notify(notif_id: u64, n: *mut Notification);
 }
 
 #[cfg(test)]
 #[no_mangle]
-pub fn engine_library_notify(notif_id: u64, n: *mut c_void) {
+pub unsafe fn engine_library_notify(_: u64, _: *mut Notification) {
     // stub for tests
+    // unsafe since it non test function is extern
 }
 
+/// Delete the Notification object.
 #[no_mangle]
-pub fn engine_library_notification_delete(n: *mut Notification) {
+pub extern "C" fn engine_library_notification_delete(n: *mut Notification) {
     unsafe { Box::from_raw(n); }
 }
 
-
 #[no_mangle]
-pub fn engine_library_notification_type(n: &Notification) -> NotificationType {
-    match *n {
-        Notification::AddedFile => NotificationType::ADDED_FILE,
-        Notification::AddedFiles => NotificationType::ADDED_FILES,
-        Notification::AddedFolder(_) => NotificationType::ADDED_FOLDER,
-        Notification::AddedKeyword(_) => NotificationType::ADDED_KEYWORD,
-        Notification::AddedLabel(_) => NotificationType::ADDED_LABEL,
-        Notification::FileMoved(_) => NotificationType::FILE_MOVED,
-        Notification::FolderContentQueried(_) => NotificationType::FOLDER_CONTENT_QUERIED,
-        Notification::FolderCounted(_) => NotificationType::FOLDER_COUNTED,
-        Notification::FolderCountChanged(_) => NotificationType::FOLDER_COUNT_CHANGE,
-        Notification::KeywordContentQueried(_) => NotificationType::KEYWORD_CONTENT_QUERIED,
-        Notification::LabelChanged(_) => NotificationType::LABEL_CHANGED,
-        Notification::LabelDeleted(_) => NotificationType::LABEL_DELETED,
-        Notification::LibCreated => NotificationType::NEW_LIBRARY_CREATED,
-        Notification::MetadataChanged(_) => NotificationType::METADATA_CHANGED,
-        Notification::MetadataQueried(_) => NotificationType::METADATA_QUERIED,
-        Notification::XmpNeedsUpdate => NotificationType::XMP_NEEDS_UPDATE,
-    }
+pub extern "C" fn engine_library_notification_type(n: *const Notification) -> i32 {
+    let t = match unsafe { n.as_ref() } {
+        Some(&Notification::AddedFile) => NotificationType::ADDED_FILE,
+        Some(&Notification::AddedFiles) => NotificationType::ADDED_FILES,
+        Some(&Notification::AddedFolder(_)) => NotificationType::ADDED_FOLDER,
+        Some(&Notification::AddedKeyword(_)) => NotificationType::ADDED_KEYWORD,
+        Some(&Notification::AddedLabel(_)) => NotificationType::ADDED_LABEL,
+        Some(&Notification::FileMoved(_)) => NotificationType::FILE_MOVED,
+        Some(&Notification::FolderContentQueried(_)) => NotificationType::FOLDER_CONTENT_QUERIED,
+        Some(&Notification::FolderCounted(_)) => NotificationType::FOLDER_COUNTED,
+        Some(&Notification::FolderCountChanged(_)) => NotificationType::FOLDER_COUNT_CHANGE,
+        Some(&Notification::KeywordContentQueried(_)) =>
+            NotificationType::KEYWORD_CONTENT_QUERIED,
+        Some(&Notification::LabelChanged(_)) => NotificationType::LABEL_CHANGED,
+        Some(&Notification::LabelDeleted(_)) => NotificationType::LABEL_DELETED,
+        Some(&Notification::LibCreated) => NotificationType::NEW_LIBRARY_CREATED,
+        Some(&Notification::MetadataChanged(_)) => NotificationType::METADATA_CHANGED,
+        Some(&Notification::MetadataQueried(_)) => NotificationType::METADATA_QUERIED,
+        Some(&Notification::XmpNeedsUpdate) => NotificationType::XMP_NEEDS_UPDATE,
+        None => unreachable!(),
+    };
+    t as i32
 }
 
+
 #[no_mangle]
-pub fn engine_library_notification_get_id(n: &Notification) -> LibraryId {
-    match *n {
-        Notification::MetadataChanged(ref changed) => {
-            changed.id
-        },
-        Notification::LabelDeleted(id) => {
-            id
-        },
-        _ => {
-            unreachable!()
-        }
+pub extern "C" fn engine_library_notification_get_id(n: *const Notification) -> LibraryId {
+    match unsafe { n.as_ref() } {
+        Some(&Notification::MetadataChanged(ref changed)) => changed.id,
+        Some(&Notification::LabelDeleted(id)) => id,
+        _ => unreachable!(),
     }
 }
 
 #[no_mangle]
-pub fn engine_library_notification_get_label(n: &Notification) -> *const Label {
-    match *n {
-        Notification::AddedLabel(ref l) => {
-            l
-        },
-        _ => {
-            unreachable!()
-        }
+pub extern "C" fn engine_library_notification_get_label(n: *const Notification) -> *const Label {
+    match unsafe { n.as_ref() } {
+        Some(&Notification::AddedLabel(ref l)) => l,
+        _ => unreachable!(),
     }
 }
 
 #[no_mangle]
-pub fn engine_library_notification_get_filemoved(n: &Notification) -> *const FileMove {
-    match *n {
-        Notification::FileMoved(ref m) => {
-            m
-        },
-        _ => {
-            unreachable!()
-        }
+pub extern "C" fn engine_library_notification_get_filemoved(n: *const Notification) -> *const FileMove {
+    match unsafe { n.as_ref() } {
+        Some(&Notification::FileMoved(ref m)) => m,
+        _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub fn engine_library_notification_get_libmetadata(n: &Notification) -> *const LibMetadata {
-    match *n {
-        Notification::MetadataQueried(ref m) => {
-            m
-        },
-        _ => {
-            unreachable!()
-        }
+pub extern "C" fn engine_library_notification_get_libmetadata(n: *const Notification) -> *const LibMetadata {
+    match unsafe { n.as_ref() } {
+        Some(&Notification::MetadataQueried(ref m)) => m,
+        _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub fn engine_library_notification_get_folder_count(n: &Notification) -> *const FolderCount {
-    match *n {
-        Notification::FolderCountChanged(ref c) |
-        Notification::FolderCounted(ref c) => {
-            c
-        },
-        _ => {
-            unreachable!()
-        }
+pub extern "C" fn engine_library_notification_get_folder_count(n: *const Notification) -> *const FolderCount 
{
+    match unsafe { n.as_ref() } {
+        Some(&Notification::FolderCountChanged(ref c)) |
+        Some(&Notification::FolderCounted(ref c)) =>
+            c,
+        _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub fn engine_library_notification_get_metadatachange(n: &Notification) -> *const MetadataChange {
-    match *n {
-        Notification::MetadataChanged(ref c) => {
-            c
-        },
-        _ => {
-            unreachable!()
-        }
+pub extern "C" fn engine_library_notification_get_metadatachange(n: *const Notification) -> *const 
MetadataChange {
+    match unsafe { n.as_ref() } {
+        Some(&Notification::MetadataChanged(ref c)) => c,
+        _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub fn engine_library_notification_get_libfolder(n: &Notification) -> *const LibFolder {
-    match *n {
-        Notification::AddedFolder(ref f) => {
-            f
-        },
-        _ => {
-            unreachable!()
-        }
+pub extern "C" fn engine_library_notification_get_libfolder(n: *const Notification) -> *const LibFolder {
+    match unsafe { n.as_ref() } {
+        Some(&Notification::AddedFolder(ref f)) => f,
+        _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub fn engine_library_notification_get_keyword(n: &Notification) -> *const Keyword {
-    match *n {
-        Notification::AddedKeyword(ref f) => {
-            f
-        },
-        _ => {
-            unreachable!()
-        }
+pub extern "C" fn engine_library_notification_get_keyword(n: *const Notification) -> *const Keyword {
+    match unsafe { n.as_ref() } {
+        Some(&Notification::AddedKeyword(ref f)) => f,
+        _ => unreachable!()
     }
 }
 
 #[no_mangle]
-pub fn engine_library_notification_get_content(n: &Notification) -> *const Content {
-    match *n {
-        Notification::FolderContentQueried(ref c) |
-        Notification::KeywordContentQueried(ref c) => {
+pub extern "C" fn engine_library_notification_get_content(n: *const Notification) -> *const Content {
+    match unsafe { n.as_ref() } {
+        Some(&Notification::FolderContentQueried(ref c)) |
+        Some(&Notification::KeywordContentQueried(ref c)) => {
             c
         },
         _ => {
diff --git a/src/fwk/base/date.hpp b/src/fwk/base/date.hpp
index 4d41668..ba92439 100644
--- a/src/fwk/base/date.hpp
+++ b/src/fwk/base/date.hpp
@@ -24,6 +24,8 @@
 
 #include <exempi/xmp.h>
 
+#include "rust_bindings.hpp"
+
 namespace fwk {
 
 class Timezone;
@@ -34,9 +36,13 @@ class Timezone;
  */
 bool make_xmp_date_time(time_t t, XmpDateTime& xmp_dt);
 
+#if RUST_BINDGEN
 class Date;
+#endif
 
 typedef std::shared_ptr<Date> DatePtr;
+
+
 DatePtr date_wrap(Date*);
 std::string date_to_string(const Date*);
 }
diff --git a/src/fwk/base/date.rs b/src/fwk/base/date.rs
index 9c02d96..0dc8032 100644
--- a/src/fwk/base/date.rs
+++ b/src/fwk/base/date.rs
@@ -30,13 +30,15 @@ use std::time::{
 // Like a UNIX time_t (also i64)
 pub type Time = i64;
 
+#[derive(Clone,Debug)]
 pub enum Timezone {}
 
-/**
- * Class to deal with ISO8601 string dates as used by XMP.
- * Bonus: with a timezone.
- * XXX replace by chrono::DateTime<>
- */
+///
+/// Class to deal with ISO8601 string dates as used by XMP.
+/// Bonus: with a timezone.
+/// XXX replace by chrono::DateTime<>
+///
+#[derive(Clone,Debug)]
 pub struct Date {
     datetime: exempi::DateTime,
     tz: Option<Timezone>,
diff --git a/src/fwk/base/mod.rs b/src/fwk/base/mod.rs
index 56b4402..799a9dc 100644
--- a/src/fwk/base/mod.rs
+++ b/src/fwk/base/mod.rs
@@ -21,6 +21,8 @@ pub mod date;
 #[macro_use]
 pub mod debug;
 pub mod fractions;
+pub mod propertybag;
+pub mod propertyvalue;
 pub mod rgbcolour;
 
 pub type PropertyIndex = u32;
diff --git a/src/fwk/base/propertybag.cpp b/src/fwk/base/propertybag.cpp
index 36b3ae5..8574119 100644
--- a/src/fwk/base/propertybag.cpp
+++ b/src/fwk/base/propertybag.cpp
@@ -23,93 +23,84 @@
 
 namespace fwk {
 
-bool is_empty(const PropertyValue & v)
+PropertyValuePtr property_value_wrap(PropertyValue* v)
 {
-    return v.type() == typeid(EmptyValue);
+    return PropertyValuePtr(v, &ffi::fwk_property_value_delete);
 }
 
-bool is_integer(const PropertyValue & v)
+PropertyValuePtr property_value_new(const std::string& v)
 {
-    return v.type() == typeid(int);
+    return property_value_wrap(ffi::fwk_property_value_new_str(v.c_str()));
 }
 
-bool is_string(const PropertyValue & v)
+PropertyValuePtr property_value_new(int v)
 {
-    return v.type() == typeid(std::string);
+    return property_value_wrap(ffi::fwk_property_value_new_int(v));
 }
 
-bool is_string_array(const PropertyValue & v)
+PropertyValuePtr property_value_new(const DatePtr& d)
 {
-    return v.type() == typeid(StringArray);
+    return property_value_wrap(ffi::fwk_property_value_new_date(d.get()));
 }
 
-bool is_date(const PropertyValue & v)
+PropertyValuePtr property_value_new(const std::vector<std::string>& sa)
 {
-    return v.type() == typeid(DatePtr);
-}
-
-int get_integer(const PropertyValue & v)
-{
-    return is_empty(v) ? 0 : boost::get<int>(v);
-}
-
-const Date* get_date(const PropertyValue & v)
-{
-    return boost::get<DatePtr>(v).get();
-}
-const std::string & get_string(const PropertyValue & v)
-{
-    return boost::get<std::string>(v);
-}
-
-const char* get_string_cstr(const PropertyValue & v)
-{
-    return boost::get<std::string>(v).c_str();
+    PropertyValue* value = ffi::fwk_property_value_new_string_array();
+    for (auto s : sa) {
+        ffi::fwk_property_value_add_string(value, s.c_str());
+    }
+    return property_value_wrap(value);
 }
 
-// Rust glue
-const fwk::StringArray & get_string_array(const PropertyValue & v)
+std::string property_value_get_string(const PropertyValue &value)
 {
-    return boost::get<fwk::StringArray>(v);
+    auto s = ffi::fwk_property_value_get_string(&value);
+    std::string str(s);
+    ffi::rust_cstring_delete(s);
+    return str;
 }
 
-size_t string_array_len(const fwk::StringArray &v)
+std::vector<std::string> property_value_get_string_array(const PropertyValue &value)
 {
-    return v.size();
+    std::vector<std::string> v;
+    auto len = ffi::fwk_property_value_count_string_array(&value);
+    for (size_t i = 0; i < len; i++) {
+        auto s = ffi::fwk_property_value_get_string_at(&value, i);
+        v.push_back(s);
+        ffi::rust_cstring_delete(s);
+    }
+    return v;
 }
 
-const char* string_array_at_cstr(const fwk::StringArray &v, size_t i)
+PropertyBagPtr property_bag_wrap(PropertyBag* bag)
 {
-    return v[i].c_str();
+    return PropertyBagPtr(bag, &ffi::fwk_property_bag_delete);
 }
-// end
 
-bool PropertyBag::set_value_for_property(PropertyIndex idx, const PropertyValue & value)
+PropertyBagPtr property_bag_new()
 {
-    bool removed = (m_bag.erase(idx) == 1);
-    m_bag.insert(std::make_pair(idx, value));
-    return removed;
+    return property_bag_wrap(ffi::fwk_property_bag_new());
 }
 
-/** return an option */
-fwk::Option<PropertyValue> PropertyBag::get_value_for_property(PropertyIndex idx) const
+PropertyValuePtr property_bag_value(const PropertyBagPtr& bag, PropertyIndex idx)
 {
-    _Map::const_iterator iter = m_bag.find(idx);
-    if(iter == m_bag.end()) {
-        return false;
-    }
-    return fwk::Option<PropertyValue>(iter->second);
+    auto value = ffi::fwk_property_bag_value(bag.get(), idx);
+    return property_value_wrap(value);
 }
 
-bool PropertyBag::has_value_for_property(PropertyIndex idx) const
+bool set_value_for_property(PropertyBag& bag, PropertyIndex idx,
+                            const PropertyValue & value)
 {
-    return m_bag.find(idx) != m_bag.end();
+    return ffi::fwk_property_bag_set_value(&bag, idx, &value);
 }
 
-bool PropertyBag::remove_value_for_property(PropertyIndex idx)
+/* return an option */
+// XXX fix me
+fwk::Option<PropertyValuePtr> get_value_for_property(const PropertyBag& bag,
+                                                     PropertyIndex idx)
 {
-    _Map::size_type sz = m_bag.erase(idx);
-    return sz == 1;
+    auto value = ffi::fwk_property_bag_value(&bag, idx);
+    return fwk::Option<PropertyValuePtr>(property_value_wrap(value));
 }
 
 }
diff --git a/src/fwk/base/propertybag.hpp b/src/fwk/base/propertybag.hpp
index 8f56cf1..6b355de 100644
--- a/src/fwk/base/propertybag.hpp
+++ b/src/fwk/base/propertybag.hpp
@@ -17,129 +17,63 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __FWK_PROPERTYBAG_HPP_
-#define __FWK_PROPERTYBAG_HPP_
+#pragma once
 
 #include <stdint.h>
 #include <string>
 #include <vector>
-#include <map>
 #include <set>
 #include <memory>
-#include <boost/variant.hpp>
 
 #include "fwk/base/date.hpp"
 #include "fwk/base/option.hpp"
 
+#include "rust_bindings.hpp"
+
 namespace fwk {
 
 typedef uint32_t PropertyIndex;
-/** The empty value */
-typedef boost::blank EmptyValue;
-typedef std::vector<std::string> StringArray;
-/** EmptyValue will be the default type */
-class PropertyValue
-    : private boost::variant<EmptyValue, int, std::string, StringArray, DatePtr>
-{
-public:
-#if !RUST_BINDGEN
-    typedef boost::variant<EmptyValue, int, std::string, StringArray, DatePtr> _inner;
-
-    PropertyValue()
-        : _inner()
-        {
-        }
-    template<class T>
-    PropertyValue(const T& data)
-        : _inner(data)
-        {
-        }
-
-    _inner& get_variant()
-        { return *this; }
-    const _inner& get_variant() const
-        { return *this; }
-#endif
-    friend bool is_empty(const PropertyValue & v);
-    friend bool is_integer(const PropertyValue & v);
-    friend bool is_string(const PropertyValue & v);
-    friend bool is_string_array(const PropertyValue & v);
-    friend bool is_date(const PropertyValue & v);
-    friend int get_integer(const PropertyValue & v);
-    friend const Date* get_date(const PropertyValue & v);
-    friend const std::string & get_string(const PropertyValue & v);
-    friend const char* get_string_cstr(const PropertyValue & v);
-    friend const fwk::StringArray & get_string_array(const PropertyValue & v);
-};
 
 typedef std::set<PropertyIndex> PropertySet;
 
-/** Return if the property value is empty */
-bool is_empty(const PropertyValue & v);
-/** Return if it is an integer */
-bool is_integer(const PropertyValue & v);
-bool is_string(const PropertyValue & v);
-bool is_string_array(const PropertyValue & v);
-bool is_date(const PropertyValue & v);
-const Date* get_date(const PropertyValue & v);
-/** Return the integer value (or 0 if empty) */
-int get_integer(const PropertyValue & v);
-/** Return the string value */
-const std::string & get_string(const PropertyValue & v);
-const char* get_string_cstr(const PropertyValue & v);
-
-// Rust glue
-const fwk::StringArray & get_string_array(const PropertyValue & v);
-size_t string_array_len(const fwk::StringArray &);
-const char* string_array_at_cstr(const fwk::StringArray &, size_t);
+#if !RUST_BINDGEN
+typedef std::shared_ptr<PropertyValue> PropertyValuePtr;
+
+PropertyValuePtr property_value_new(const std::string&);
+PropertyValuePtr property_value_new(int);
+PropertyValuePtr property_value_new(const std::vector<std::string>&);
+PropertyValuePtr property_value_new(const DatePtr&);
+
+std::string property_value_get_string(const PropertyValue &value);
+std::vector<std::string> property_value_get_string_array(const PropertyValue &value);
+#endif
+
+#if RUST_BINDGEN
+class PropertyBag;
+#endif
 
 /** a property bag
  * It is important that the values for PropertyIndex be properly name spaced
  * by the caller.
  */
-class PropertyBag
-{
-public:
-    typedef std::shared_ptr<PropertyBag> Ptr;
-    typedef std::map<PropertyIndex, PropertyValue> _Map;
-    typedef _Map::const_iterator const_iterator;
-    typedef _Map::value_type value_type;
-
-    bool empty() const
-        {
-            return m_bag.empty();
-        }
-
-    const_iterator begin() const
-        {
-            return m_bag.cbegin();
-        }
-    const_iterator end() const
-        {
-            return m_bag.cend();
-        }
-    const_iterator cbegin() const
-        {
-            return m_bag.cbegin();
-        }
-    const_iterator cend() const
-        {
-            return m_bag.cend();
-        }
-
-
-    /** return true if a property was removed prior to insertion */
-    bool set_value_for_property(PropertyIndex idx, const PropertyValue & value);
-    /** return property or an empty option */
-    fwk::Option<PropertyValue> get_value_for_property(PropertyIndex idx) const;
-    /** return true if property exist */
-    bool has_value_for_property(PropertyIndex idx) const;
-    /** return true if the property was removed */
-    bool remove_value_for_property(PropertyIndex idx);
-private:
-    _Map    m_bag;
-};
+typedef std::shared_ptr<PropertyBag> PropertyBagPtr;
+
+#if !RUST_BINDGEN
+PropertyBagPtr property_bag_new();
+
+PropertyValuePtr property_bag_value(const PropertyBagPtr& bag, PropertyIndex key);
 
+std::string property_value_get_string(const PropertyValue& v);
+
+/** return true if a property was removed prior to insertion */
+bool set_value_for_property(PropertyBag&, PropertyIndex idx, const PropertyValue & value);
+/** return property or an empty option */
+fwk::Option<PropertyValuePtr> get_value_for_property(const PropertyBag&, PropertyIndex idx);
+/** return true if property exist */
+bool has_value_for_property(const PropertyBag&, PropertyIndex idx);
+/** return true if the property was removed */
+bool remove_value_for_property(PropertyBag&, PropertyIndex idx);
+#endif
 
 }
 
@@ -152,4 +86,3 @@ private:
   fill-column:99
   End:
 */
-#endif
diff --git a/src/fwk/base/propertybag.rs b/src/fwk/base/propertybag.rs
new file mode 100644
index 0000000..2f6c33b
--- /dev/null
+++ b/src/fwk/base/propertybag.rs
@@ -0,0 +1,119 @@
+/*
+ * niepce - fwk/base/propertybag.rs
+ *
+ * Copyright (C) 2017 Hubert Figuière
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+use std::collections::BTreeMap;
+use std::ptr;
+
+use fwk::base::PropertyIndex;
+use fwk::base::propertyvalue::PropertyValue;
+
+pub struct PropertyBag {
+    pub bag: Vec<PropertyIndex>,
+    pub map: BTreeMap<PropertyIndex, PropertyValue>,
+}
+
+impl PropertyBag {
+
+    pub fn new() -> Self {
+        PropertyBag{ bag: Vec::new(), map: BTreeMap::new() }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.bag.is_empty()
+    }
+
+    pub fn len(&self) -> usize {
+        self.bag.len()
+    }
+
+    pub fn set_value(&mut self, key: PropertyIndex, value: PropertyValue) -> bool {
+        let ret = self.map.insert(key, value);
+        if ret.is_some() {
+            return true;
+        }
+        self.bag.push(key);
+        false
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_bag_new() -> *mut PropertyBag {
+    Box::into_raw(Box::new(PropertyBag::new()))
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_bag_delete(bag: *mut PropertyBag) {
+    unsafe { Box::from_raw(bag); }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_bag_is_empty(b: *const PropertyBag) -> bool {
+    match unsafe { b.as_ref() } {
+        Some(ref pb) => pb.is_empty(),
+        None => true
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_bag_len(b: *const PropertyBag) -> usize {
+    match unsafe { b.as_ref() } {
+        Some(ref pb) => pb.len(),
+        None => unreachable!()
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_bag_key_by_index(b: *const PropertyBag, idx: usize)
+                                         -> PropertyIndex {
+    match unsafe { b.as_ref() } {
+        Some(ref pb) => pb.bag[idx],
+        None => unreachable!()
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_bag_value(b: *const PropertyBag, key: PropertyIndex)
+                                         -> *mut PropertyValue {
+    match unsafe { b.as_ref() } {
+        Some(ref pb) => {
+            if pb.map.contains_key(&key) {
+                let value = Box::new(pb.map[&key].clone());
+                Box::into_raw(value)
+            } else {
+                ptr::null_mut()
+            }
+        },
+        None => unreachable!()
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_bag_set_value(b: *mut PropertyBag, key: PropertyIndex,
+                                             v: *const PropertyValue) -> bool {
+    let value = match unsafe { v.as_ref() } {
+        Some(value) => value.clone(),
+        None => unreachable!()
+    };
+    match unsafe { b.as_mut() } {
+        Some(ref mut pb) => {
+            pb.set_value(key, value)
+        },
+        None => unreachable!()
+    }
+}
diff --git a/src/fwk/base/propertyvalue.rs b/src/fwk/base/propertyvalue.rs
new file mode 100644
index 0000000..e91dd7b
--- /dev/null
+++ b/src/fwk/base/propertyvalue.rs
@@ -0,0 +1,160 @@
+/*
+ * niepce - fwk/base/propertyvalue.rs
+ *
+ * Copyright (C) 2017 Hubert Figuière
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+use libc::c_char;
+use std::ffi::{CStr,CString};
+use fwk::base::date::Date;
+
+
+#[derive(Clone,Debug)]
+#[repr(C)]
+pub enum PropertyValue {
+    Empty,
+    Int(i32),
+    String(String),
+    StringArray(Vec<String>),
+    Date(Date)
+}
+
+
+impl PropertyValue {
+
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_new_str(v: *const c_char) -> *mut PropertyValue {
+    let cstr = unsafe { CStr::from_ptr(v) };
+    let value = Box::new(PropertyValue::String(cstr.to_string_lossy().into_owned()));
+    Box::into_raw(value)
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_new_int(v: i32) -> *mut PropertyValue {
+    let value = Box::new(PropertyValue::Int(v));
+    Box::into_raw(value)
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_new_date(v: &Date) -> *mut PropertyValue {
+    let value = Box::new(PropertyValue::Date(v.clone()));
+    Box::into_raw(value)
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_new_string_array() -> *mut PropertyValue {
+    let value = Box::new(PropertyValue::StringArray(vec!()));
+    Box::into_raw(value)
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_delete(v: *mut PropertyValue) {
+    if !v.is_null() {
+        unsafe { Box::from_raw(v); }
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_is_empty(v: *const PropertyValue) -> bool {
+    match unsafe { v.as_ref() } {
+        Some(&PropertyValue::Empty) => true,
+        _ => false
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_is_integer(v: *const PropertyValue) -> bool {
+    match unsafe { v.as_ref() } {
+        Some(&PropertyValue::Int(_)) => true,
+        _ => false
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_get_integer(v: *const PropertyValue) -> i32 {
+    match unsafe { v.as_ref() } {
+        Some(&PropertyValue::Int(i)) => i,
+        _ => unreachable!()
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_is_date(v: *const PropertyValue) -> bool {
+    match unsafe { v.as_ref() } {
+        Some(&PropertyValue::Date(_)) => true,
+        _ => false
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_get_date(v: *const PropertyValue) -> *const Date {
+    match unsafe { v.as_ref() } {
+        Some(&PropertyValue::Date(ref d)) => d,
+        _ => unreachable!()
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_is_string(v: *const PropertyValue) -> bool {
+    match unsafe { v.as_ref() } {
+        Some(&PropertyValue::String(_)) => true,
+        _ => false
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_get_string(v: *const PropertyValue) -> *mut c_char {
+    match unsafe { v.as_ref() } {
+        Some(&PropertyValue::String(ref s)) => {
+            CString::new(s.as_bytes()).unwrap().into_raw()
+        },
+        _ => unreachable!()
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_add_string(v: *mut PropertyValue, str: *const c_char) {
+    match unsafe { v.as_mut() } {
+        Some(&mut PropertyValue::StringArray(ref mut sa)) => {
+            sa.push(unsafe { CStr::from_ptr(str) }.to_string_lossy().into_owned());
+        },
+        _ => unreachable!()
+    }
+
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_count_string_array(v: *const PropertyValue) -> usize {
+    match unsafe { v.as_ref() } {
+        Some(&PropertyValue::StringArray(ref sa)) => {
+            sa.len()
+        },
+        _ => unreachable!()
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_value_get_string_at(v: *const PropertyValue, idx: usize)
+                                                   -> *mut c_char {
+    match unsafe { v.as_ref() } {
+        Some(&PropertyValue::StringArray(ref sa)) => {
+            CString::new(sa[idx].as_bytes()).unwrap().into_raw()
+        },
+        _ => unreachable!()
+    }
+}
diff --git a/src/fwk/mod.rs b/src/fwk/mod.rs
index 0f7a0ea..9c5fe5d 100644
--- a/src/fwk/mod.rs
+++ b/src/fwk/mod.rs
@@ -28,7 +28,8 @@ pub use self::utils::exempi::{
     XmpMeta,
     gps_coord_from_xmp
 };
-
+pub use self::base::propertyvalue::PropertyValue;
+pub use self::base::propertybag::PropertyBag;
 pub use self::base::fractions::{
     fraction_to_decimal
 };
diff --git a/src/fwk/toolkit/metadatawidget.cpp b/src/fwk/toolkit/metadatawidget.cpp
index d4db88b..906cefd 100644
--- a/src/fwk/toolkit/metadatawidget.cpp
+++ b/src/fwk/toolkit/metadatawidget.cpp
@@ -38,13 +38,10 @@
 #include "fwk/toolkit/widgets/notabtextview.hpp"
 #include "fwk/toolkit/widgets/tokentextview.hpp"
 
-// remove
-//#include "engine/db/properties.hpp"
+#include "rust_bindings.hpp"
 
 #include "metadatawidget.hpp"
 
-
-
 namespace fwk {
 
 MetaDataWidget::MetaDataWidget(const Glib::ustring & title)
@@ -225,7 +222,7 @@ void MetaDataWidget::clear_widget(const std::pair<const PropertyIndex, Gtk::Widg
     }
 }
 
-void MetaDataWidget::set_data_source(const fwk::PropertyBag & properties)
+void MetaDataWidget::set_data_source(const fwk::PropertyBagPtr& properties)
 {
     DBG_OUT("set data source");
     m_current_data = properties;
@@ -235,8 +232,9 @@ void MetaDataWidget::set_data_source(const fwk::PropertyBag & properties)
                           this->clear_widget(p);
                       });
     }
-    set_sensitive(!properties.empty());
-    if(properties.empty()) {
+    bool is_empty = fwk_property_bag_is_empty(properties.get());
+    set_sensitive(!is_empty);
+    if(is_empty) {
         return;
     }
     if(!m_fmt) {
@@ -246,9 +244,9 @@ void MetaDataWidget::set_data_source(const fwk::PropertyBag & properties)
 
     const MetaDataFormat * current = m_fmt->formats;
     while(current && current->label) {
-        auto result = properties.get_value_for_property(current->id);
+        auto result = get_value_for_property(*properties, current->id);
         if(!result.empty() || !current->readonly) {
-            add_data(current, result.unwrap());
+            add_data(current, *result.unwrap());
         }
         else {
             DBG_OUT("get_property failed id = %d, label = %s",
@@ -261,12 +259,12 @@ void MetaDataWidget::set_data_source(const fwk::PropertyBag & properties)
 bool MetaDataWidget::set_fraction_dec_data(Gtk::Widget* w,
                                            const PropertyValue & value)
 {
-    if (!is_string(value)) {
+    if (!fwk_property_value_is_string(&value)) {
         ERR_OUT("Data not string(fraction)");
         return false;
     }
     try {
-        const std::string& str_value = get_string(value);
+        const std::string str_value = fwk::property_value_get_string(value);
         DBG_OUT("set fraction dec %s", str_value.c_str());
         std::string frac = str(boost::format("%.1f")
                                % fwk_fraction_to_decimal(str_value.c_str()));
@@ -282,15 +280,15 @@ bool MetaDataWidget::set_fraction_dec_data(Gtk::Widget* w,
 bool MetaDataWidget::set_fraction_data(Gtk::Widget* w,
                                        const PropertyValue & value)
 {
-    if (!is_string(value)) {
+    if (!fwk_property_value_is_string(&value)) {
         ERR_OUT("Data not string(fraction)");
         return false;
     }
     try {
-        const std::string& str_value = get_string(value);
+        const std::string str_value = fwk::property_value_get_string(value);
         DBG_OUT("set fraction %s", str_value.c_str());
         boost::rational<int> r
-            = boost::lexical_cast<boost::rational<int> >(str_value);
+            = boost::lexical_cast<boost::rational<int>>(str_value);
 
         std::string frac = str(boost::format("%1%/%2%")
                                % r.numerator() % r.denominator());
@@ -306,12 +304,12 @@ bool MetaDataWidget::set_fraction_data(Gtk::Widget* w,
 bool MetaDataWidget::set_star_rating_data(Gtk::Widget* w,
                                           const PropertyValue & value)
 {
-    if (!is_integer(value)) {
+    if (!fwk_property_value_is_integer(&value)) {
         ERR_OUT("Data not integer");
         return false;
     }
     try {
-        int rating = get_integer(value);
+        int rating = fwk_property_value_get_integer(&value);
         AutoFlag flag(m_update);
         static_cast<fwk::RatingLabel*>(w)->set_rating(rating);
     }
@@ -325,7 +323,7 @@ bool MetaDataWidget::set_string_array_data(Gtk::Widget* w, const PropertyValue &
 {
     try {
         AutoFlag flag(m_update);
-        fwk::StringArray tokens = boost::get<fwk::StringArray>(value.get_variant());
+        std::vector<std::string> tokens = fwk::property_value_get_string_array(value);
 
         static_cast<fwk::TokenTextView*>(w)->set_tokens(tokens);
     }
@@ -338,17 +336,18 @@ bool MetaDataWidget::set_string_array_data(Gtk::Widget* w, const PropertyValue &
 bool MetaDataWidget::set_text_data(Gtk::Widget* w, bool readonly,
                                    const PropertyValue & value)
 {
-    if (!is_string(value)) {
-        ERR_OUT("Data not string");
+    if (!fwk_property_value_is_string(&value)) {
+        ERR_OUT("Data not string.");
         return false;
     }
     try {
         AutoFlag flag(m_update);
         if(readonly) {
-            static_cast<Gtk::Label*>(w)->set_text(get_string(value));
-        }
-        else {
-            static_cast<Gtk::TextView*>(w)->get_buffer()->set_text(get_string(value));
+            static_cast<Gtk::Label*>(w)->set_text(
+                fwk::property_value_get_string(value));
+        } else {
+            static_cast<Gtk::TextView*>(w)->get_buffer()->set_text(
+                fwk::property_value_get_string(value));
         }
     }
     catch(...) {
@@ -360,17 +359,18 @@ bool MetaDataWidget::set_text_data(Gtk::Widget* w, bool readonly,
 bool MetaDataWidget::set_string_data(Gtk::Widget* w, bool readonly,
                                      const PropertyValue & value)
 {
-    if (!is_string(value)) {
-        ERR_OUT("Data not string");
+    if (!fwk_property_value_is_string(&value)) {
+        ERR_OUT("Data not string.");
         return false;
     }
     try {
         AutoFlag flag(m_update);
         if(readonly) {
-            static_cast<Gtk::Label*>(w)->set_text(get_string(value));
-        }
-        else {
-            static_cast<Gtk::Entry*>(w)->set_text(get_string(value));
+            static_cast<Gtk::Label*>(w)->set_text(
+                fwk::property_value_get_string(value));
+        } else {
+            static_cast<Gtk::Entry*>(w)->set_text(
+                fwk::property_value_get_string(value));
         }
     }
     catch(...) {
@@ -381,12 +381,19 @@ bool MetaDataWidget::set_string_data(Gtk::Widget* w, bool readonly,
 
 bool MetaDataWidget::set_date_data(Gtk::Widget* w, const PropertyValue & value)
 {
+    if (!fwk_property_value_is_date(&value)) {
+        return false;
+    }
     try {
         AutoFlag flag(m_update);
-        fwk::DatePtr date = boost::get<fwk::DatePtr>(value.get_variant());
-        static_cast<Gtk::Label*>(w)->set_text(fwk::date_to_string(date.get()));
+        const fwk::Date* date = fwk_property_value_get_date(&value);
+        if (date) {
+            static_cast<Gtk::Label*>(w)->set_text(fwk::date_to_string(date));
 
-        DBG_OUT("setting date data %s", fwk::date_to_string(date.get()).c_str());
+            DBG_OUT("setting date data %s", fwk::date_to_string(date).c_str());
+        } else {
+            return false;
+        }
     }
     catch(...) {
         return false;
@@ -397,7 +404,7 @@ bool MetaDataWidget::set_date_data(Gtk::Widget* w, const PropertyValue & value)
 void MetaDataWidget::add_data(const MetaDataFormat * current,
                               const PropertyValue & value)
 {
-    if (is_empty(value)) {
+    if (fwk_property_value_is_empty(&value)) {
         return;
     }
 
@@ -430,34 +437,36 @@ void MetaDataWidget::add_data(const MetaDataFormat * current,
         set_date_data(w, value);
         break;
     default:
-        set_string_data(w, current->readonly, value);
+        if (!set_string_data(w, current->readonly, value)) {
+            ERR_OUT("failed to set value for %ld", current->id);
+        }
         break;
     }
 }
 
-bool MetaDataWidget::on_str_changed(GdkEventFocus*, Gtk::Entry *e, 
+bool MetaDataWidget::on_str_changed(GdkEventFocus*, Gtk::Entry *e,
                                     fwk::PropertyIndex prop)
 {
     if(m_update) {
         return true;
     }
-    emit_metadata_changed(prop, fwk::PropertyValue(e->get_text()));
+    emit_metadata_changed(prop, fwk::property_value_new(e->get_text()));
     return true;
 }
 
-bool MetaDataWidget::on_text_changed(GdkEventFocus*, 
-                                     Glib::RefPtr<Gtk::TextBuffer> b, 
+bool MetaDataWidget::on_text_changed(GdkEventFocus*,
+                                     Glib::RefPtr<Gtk::TextBuffer> b,
                                      fwk::PropertyIndex prop)
 {
     if(m_update) {
         return true;
     }
     emit_metadata_changed(prop,
-                          fwk::PropertyValue(b->get_text()));
+                          fwk::property_value_new(b->get_text()));
     return true;
 }
 
-bool MetaDataWidget::on_string_array_changed(GdkEventFocus*, 
+bool MetaDataWidget::on_string_array_changed(GdkEventFocus*,
                                              fwk::TokenTextView * ttv,
                                              fwk::PropertyIndex prop)
 {
@@ -466,8 +475,8 @@ bool MetaDataWidget::on_string_array_changed(GdkEventFocus*,
     }
     fwk::TokenTextView::Tokens tok;
     ttv->get_tokens(tok);
-    emit_metadata_changed(prop, 
-                          fwk::PropertyValue(tok));
+    emit_metadata_changed(prop,
+                          fwk::property_value_new(tok));
     return true;
 }
 
@@ -476,17 +485,18 @@ void MetaDataWidget::on_int_changed(int value, fwk::PropertyIndex prop)
     if(m_update) {
         return;
     }
-    emit_metadata_changed(prop, fwk::PropertyValue(value));
+    emit_metadata_changed(prop, fwk::property_value_new(value));
 }
 
 void MetaDataWidget::emit_metadata_changed(fwk::PropertyIndex prop,
-                                           const fwk::PropertyValue & value)
+                                           const fwk::PropertyValuePtr & value)
 {
-    fwk::PropertyBag props, old_props;
-    props.set_value_for_property(prop, value);
-    auto result = m_current_data.get_value_for_property(prop);
+    fwk::PropertyBagPtr props = fwk::property_bag_new();
+    fwk::PropertyBagPtr old_props = fwk::property_bag_new();
+    fwk::set_value_for_property(*props, prop, *value);
+    auto result = fwk::get_value_for_property(*m_current_data, prop);
     if (!result.empty()) {
-        old_props.set_value_for_property(prop, result.unwrap());
+        set_value_for_property(*old_props, prop, *result.unwrap());
     }
     signal_metadata_changed.emit(props, old_props);
 }
diff --git a/src/fwk/toolkit/metadatawidget.hpp b/src/fwk/toolkit/metadatawidget.hpp
index 8bf237e..78d3483 100644
--- a/src/fwk/toolkit/metadatawidget.hpp
+++ b/src/fwk/toolkit/metadatawidget.hpp
@@ -71,9 +71,9 @@ public:
     void add_data(const MetaDataFormat * current,
                   const PropertyValue & value);
     void set_data_format(const MetaDataSectionFormat * fmt);
-    void set_data_source(const fwk::PropertyBag & properties);
+    void set_data_source(const fwk::PropertyBagPtr& properties);
 
-    sigc::signal<void, const fwk::PropertyBag &, const fwk::PropertyBag &> signal_metadata_changed;
+    sigc::signal<void, const fwk::PropertyBagPtr &, const fwk::PropertyBagPtr &> signal_metadata_changed;
 protected:
     bool on_str_changed(GdkEventFocus*, Gtk::Entry *, fwk::PropertyIndex prop);
     bool on_text_changed(GdkEventFocus*, Glib::RefPtr<Gtk::TextBuffer> b, fwk::PropertyIndex prop);
@@ -104,11 +104,11 @@ private:
                          const PropertyValue & value);
     bool set_date_data(Gtk::Widget* w, const PropertyValue & value);
 
-    void emit_metadata_changed(fwk::PropertyIndex prop, const fwk::PropertyValue & value);
+    void emit_metadata_changed(fwk::PropertyIndex prop, const fwk::PropertyValuePtr & value);
 
     Gtk::Grid    m_table;
     std::map<const PropertyIndex, Gtk::Widget *> m_data_map;
-    fwk::PropertyBag m_current_data;
+    fwk::PropertyBagPtr m_current_data;
     const MetaDataSectionFormat * m_fmt;
     bool m_update;
 };
diff --git a/src/fwk/utils/exempi.hpp b/src/fwk/utils/exempi.hpp
index 327a7f9..1582632 100644
--- a/src/fwk/utils/exempi.hpp
+++ b/src/fwk/utils/exempi.hpp
@@ -28,6 +28,8 @@
 
 #include "fwk/base/util.hpp"
 
+#include "rust_bindings.hpp"
+
 namespace xmp {
 
 inline
@@ -85,7 +87,9 @@ extern const char * UFRAW_INTEROP_NS_PREFIX;
 
 namespace fwk {
 
+#if RUST_BINDGEN
 class Date;
+#endif
 
 class XmpMeta;
 class ExempiManager;
diff --git a/src/lib.rs b/src/lib.rs
index b50bfe3..a46cf05 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -27,13 +27,6 @@ extern crate rusqlite;
 #[macro_use]
 pub mod fwk;
 pub mod engine;
+pub mod capi;
 
 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
-
-use libc::c_char;
-use std::ffi::CString;
-
-#[no_mangle]
-pub fn rust_cstring_delete(string: *mut c_char) {
-    unsafe { CString::from_raw(string); }
-}
diff --git a/src/libraryclient/clientimpl.cpp b/src/libraryclient/clientimpl.cpp
index 23238ec..f29a89c 100644
--- a/src/libraryclient/clientimpl.cpp
+++ b/src/libraryclient/clientimpl.cpp
@@ -112,10 +112,10 @@ tid_t ClientImpl::requestMetadata(eng::library_id_t file_id)
 
 
 tid_t ClientImpl::setMetadata(eng::library_id_t file_id, int meta,
-                              const fwk::PropertyValue & value)
+                              const fwk::PropertyValuePtr & value)
 {
     return schedule_op([file_id, meta, value](const auto& lib) {
-            return cmd_set_metadata(lib, file_id, meta, &value);
+            return cmd_set_metadata(lib, file_id, meta, value.get());
         });
 }
 
diff --git a/src/libraryclient/clientimpl.hpp b/src/libraryclient/clientimpl.hpp
index e068a3c..333358b 100644
--- a/src/libraryclient/clientimpl.hpp
+++ b/src/libraryclient/clientimpl.hpp
@@ -49,7 +49,7 @@ public:
     eng::tid_t countFolder(eng::library_id_t id);
     eng::tid_t requestMetadata(eng::library_id_t id);
     eng::tid_t setMetadata(eng::library_id_t id, int meta,
-                           const fwk::PropertyValue & value);
+                           const fwk::PropertyValuePtr & value);
     eng::tid_t write_metadata(eng::library_id_t file_id);
 
     eng::tid_t moveFileToFolder(eng::library_id_t file_id,
diff --git a/src/libraryclient/libraryclient.cpp b/src/libraryclient/libraryclient.cpp
index a41f3be..a709d92 100644
--- a/src/libraryclient/libraryclient.cpp
+++ b/src/libraryclient/libraryclient.cpp
@@ -89,8 +89,8 @@ eng::tid_t LibraryClient::requestMetadata(eng::library_id_t id)
 }
 
 /** set the metadata */
-eng::tid_t LibraryClient::setMetadata(library_id_t id, fwk::PropertyIndex meta, 
-                                      const fwk::PropertyValue & value)
+eng::tid_t LibraryClient::setMetadata(library_id_t id, fwk::PropertyIndex meta,
+                                      const fwk::PropertyValuePtr & value)
 {
     return m_pImpl->setMetadata(id, meta, value);
 }
diff --git a/src/libraryclient/libraryclient.hpp b/src/libraryclient/libraryclient.hpp
index ad17298..2fe91f0 100644
--- a/src/libraryclient/libraryclient.hpp
+++ b/src/libraryclient/libraryclient.hpp
@@ -66,7 +66,8 @@ public:
     eng::tid_t requestMetadata(eng::library_id_t id);
 
     /** set the metadata */
-    eng::tid_t setMetadata(eng::library_id_t id, fwk::PropertyIndex meta, const fwk::PropertyValue & value);
+    eng::tid_t setMetadata(eng::library_id_t id, fwk::PropertyIndex meta,
+                           const fwk::PropertyValuePtr & value);
     eng::tid_t moveFileToFolder(eng::library_id_t file_id, eng::library_id_t from_folder,
                                 eng::library_id_t to_folder);
     eng::tid_t write_metadata(eng::library_id_t file_id);
diff --git a/src/niepce/modules/map/mapmodule.cpp b/src/niepce/modules/map/mapmodule.cpp
index 56b6fc5..47847c0 100644
--- a/src/niepce/modules/map/mapmodule.cpp
+++ b/src/niepce/modules/map/mapmodule.cpp
@@ -71,33 +71,35 @@ MapModule::on_lib_notification(const eng::LibNotification &ln)
     if (!m_active) {
         return;
     }
-    switch(engine_library_notification_type(&ln)) {
+    switch(static_cast<eng::LibNotificationType>(engine_library_notification_type(&ln))) {
     case eng::LibNotificationType::METADATA_QUERIED:
     {
         auto lm = engine_library_notification_get_libmetadata(&ln);
         DBG_OUT("received metadata in MapModule");
 
         if (lm) {
-            fwk::PropertyBag properties;
+            fwk::PropertyBagPtr properties;
             const fwk::PropertySet propset = { eng::NpExifGpsLongProp,
                                                eng::NpExifGpsLatProp };
             eng::libmetadata_to_properties(lm, propset, properties);
             double latitude, longitude;
             latitude = longitude = NAN;
-            auto result = properties.get_value_for_property(eng::NpExifGpsLongProp);
+            auto result = fwk::get_value_for_property(*properties, eng::NpExifGpsLongProp);
             if (!result.empty()) {
-                fwk::PropertyValue val = result.unwrap();
+                fwk::PropertyValuePtr val = result.unwrap();
                 // it is a string
-                if (is_string(val)) {
-                    longitude = fwk_gps_coord_from_xmp(fwk::get_string(val).c_str());
+                if (fwk_property_value_is_string(val.get())) {
+                    longitude = fwk_gps_coord_from_xmp(
+                        fwk::property_value_get_string(*val).c_str());
                 }
             }
-            result = properties.get_value_for_property(eng::NpExifGpsLatProp);
+            result = fwk::get_value_for_property(*properties, eng::NpExifGpsLatProp);
             if (!result.empty()) {
-                fwk::PropertyValue val = result.unwrap();
+                fwk::PropertyValuePtr val = result.unwrap();
                 // it is a string
-                if (is_string(val)) {
-                    latitude = fwk_gps_coord_from_xmp(fwk::get_string(val).c_str());
+                if (fwk_property_value_is_string(val.get())) {
+                    latitude = fwk_gps_coord_from_xmp(
+                        fwk::property_value_get_string(*val).c_str());
                 }
             }
 
diff --git a/src/niepce/ui/gridviewmodule.cpp b/src/niepce/ui/gridviewmodule.cpp
index 5ffd0a6..aa62d9c 100644
--- a/src/niepce/ui/gridviewmodule.cpp
+++ b/src/niepce/ui/gridviewmodule.cpp
@@ -54,7 +54,7 @@ GridViewModule::~GridViewModule()
 void
 GridViewModule::on_lib_notification(const eng::LibNotification &ln)
 {
-    switch(engine_library_notification_type(&ln)) {
+    switch(static_cast<eng::LibNotificationType>(engine_library_notification_type(&ln))) {
     case eng::LibNotificationType::METADATA_QUERIED:
     {
         auto lm = engine_library_notification_get_libmetadata(&ln);
@@ -185,7 +185,8 @@ void GridViewModule::select_image(eng::library_id_t id)
 }
 
 
-void GridViewModule::on_metadata_changed(const fwk::PropertyBag & props, const fwk::PropertyBag & old)
+void GridViewModule::on_metadata_changed(const fwk::PropertyBagPtr & props,
+                                         const fwk::PropertyBagPtr & old)
 {
     // TODO this MUST be more generic
     DBG_OUT("on_metadata_changed()");
diff --git a/src/niepce/ui/gridviewmodule.hpp b/src/niepce/ui/gridviewmodule.hpp
index 4099f64..3de4480 100644
--- a/src/niepce/ui/gridviewmodule.hpp
+++ b/src/niepce/ui/gridviewmodule.hpp
@@ -78,7 +78,7 @@ protected:
 
 
 private:
-  void on_metadata_changed(const fwk::PropertyBag &, const fwk::PropertyBag & old);
+  void on_metadata_changed(const fwk::PropertyBagPtr&, const fwk::PropertyBagPtr& old);
   void on_rating_changed(int id, int rating);
   bool on_librarylistview_click(GdkEventButton *e);
 
diff --git a/src/niepce/ui/imageliststore.cpp b/src/niepce/ui/imageliststore.cpp
index c367dac..7ecadbd 100644
--- a/src/niepce/ui/imageliststore.cpp
+++ b/src/niepce/ui/imageliststore.cpp
@@ -29,6 +29,8 @@
 #include "niepce/notifications.hpp"
 #include "niepcewindow.hpp"
 
+#include "rust_bindings.hpp"
+
 namespace ui {
 
 Glib::RefPtr<Gdk::Pixbuf> ImageListStore::get_loading_icon()
@@ -90,16 +92,17 @@ Gtk::TreePath ImageListStore::get_path_from_id(eng::library_id_t id)
 
 void ImageListStore::on_lib_notification(const eng::LibNotification &ln)
 {
-    switch (engine_library_notification_type(&ln)) {
+    auto type = static_cast<eng::LibNotificationType>(engine_library_notification_type(&ln));
+    switch (type) {
     case eng::LibNotificationType::FOLDER_CONTENT_QUERIED:
     case eng::LibNotificationType::KEYWORD_CONTENT_QUERIED:
     {
         auto param = engine_library_notification_get_content(&ln);
         const auto& l = param->files;
-        if (engine_library_notification_type(&ln) == eng::LibNotificationType::FOLDER_CONTENT_QUERIED) {
+        if (type == eng::LibNotificationType::FOLDER_CONTENT_QUERIED) {
             m_current_folder = param->container;
             m_current_keyword = 0;
-        } else if (engine_library_notification_type(&ln) == 
eng::LibNotificationType::KEYWORD_CONTENT_QUERIED) {
+        } else if (type == eng::LibNotificationType::KEYWORD_CONTENT_QUERIED) {
             m_current_folder = 0;
             m_current_keyword = param->container;
         }
@@ -155,7 +158,7 @@ void ImageListStore::on_lib_notification(const eng::LibNotification &ln)
                 //
                 eng::LibFilePtr file = row[m_columns.m_libfile];
                 engine_db_libfile_set_property(
-                    file.get(), prop, boost::get<int32_t>(m->value.get_variant()));
+                    file.get(), prop, fwk_property_value_get_integer(m->value));
                 row[m_columns.m_libfile] = file;
             }
         }
diff --git a/src/niepce/ui/metadatapanecontroller.cpp b/src/niepce/ui/metadatapanecontroller.cpp
index a44e679..6e25e9f 100644
--- a/src/niepce/ui/metadatapanecontroller.cpp
+++ b/src/niepce/ui/metadatapanecontroller.cpp
@@ -24,6 +24,7 @@
 #include "fwk/base/debug.hpp"
 #include "fwk/toolkit/metadatawidget.hpp"
 #include "engine/db/properties.hpp"
+#include "engine/db/libmetadata.hpp"
 #include "metadatapanecontroller.hpp"
 
 namespace ui {
@@ -135,22 +136,21 @@ MetaDataPaneController::buildWidget()
 
     return m_widget;
 }
-  
-void MetaDataPaneController::on_metadata_changed(const fwk::PropertyBag & props,
-                                                 const fwk::PropertyBag & old)
+
+void MetaDataPaneController::on_metadata_changed(const fwk::PropertyBagPtr& props,
+                                                 const fwk::PropertyBagPtr& old)
 {
     signal_metadata_changed.emit(props, old);
 }
 
-
 void MetaDataPaneController::display(eng::library_id_t file_id, const eng::LibMetadata* meta)
 {
     m_fileid = file_id;
     DBG_OUT("displaying metadata");
-    fwk::PropertyBag properties;
+    fwk::PropertyBagPtr properties;
     if(meta) {
         const fwk::PropertySet & propset = get_property_set();
-        libmetadata_to_properties(meta, propset, properties);
+        eng::libmetadata_to_properties(meta, propset, properties);
     }
     std::for_each(m_widgets.begin(), m_widgets.end(),
                   [properties] (auto w) {
diff --git a/src/niepce/ui/metadatapanecontroller.hpp b/src/niepce/ui/metadatapanecontroller.hpp
index a9c3afe..2a6145a 100644
--- a/src/niepce/ui/metadatapanecontroller.hpp
+++ b/src/niepce/ui/metadatapanecontroller.hpp
@@ -24,6 +24,7 @@
 
 #include "engine/db/librarytypes.hpp"
 #include "engine/db/libmetadata.hpp"
+#include "fwk/base/propertybag.hpp"
 #include "fwk/utils/exempi.hpp"
 #include "fwk/toolkit/dockable.hpp"
 
@@ -31,7 +32,6 @@ namespace fwk {
 struct MetaDataSectionFormat;
 class MetaDataWidget;
 class Dock;
-class PropertyBag;
 }
 
 namespace ui {
@@ -48,10 +48,10 @@ public:
     eng::library_id_t displayed_file() const
         { return m_fileid; }
 
-    sigc::signal<void, const fwk::PropertyBag &, const fwk::PropertyBag &> signal_metadata_changed;
+    sigc::signal<void, const fwk::PropertyBagPtr &, const fwk::PropertyBagPtr &> signal_metadata_changed;
 private:
-    void on_metadata_changed(const fwk::PropertyBag &,
-                             const fwk::PropertyBag & old);
+    void on_metadata_changed(const fwk::PropertyBagPtr &,
+                             const fwk::PropertyBagPtr & old);
 
     std::vector<fwk::MetaDataWidget *> m_widgets;
 
diff --git a/src/niepce/ui/niepcewindow.cpp b/src/niepce/ui/niepcewindow.cpp
index 5bcfdf3..e0efdfc 100644
--- a/src/niepce/ui/niepcewindow.cpp
+++ b/src/niepce/ui/niepcewindow.cpp
@@ -336,7 +336,7 @@ void NiepceWindow::create_initial_labels()
 
 void NiepceWindow::on_lib_notification(const eng::LibNotification& ln)
 {
-    switch(engine_library_notification_type(&ln)) {
+    switch(static_cast<eng::LibNotificationType>(engine_library_notification_type(&ln))) {
     case eng::LibNotificationType::NEW_LIBRARY_CREATED:
         create_initial_labels();
         break;
diff --git a/src/niepce/ui/selectioncontroller.cpp b/src/niepce/ui/selectioncontroller.cpp
index 9fb9d28..2243fb9 100644
--- a/src/niepce/ui/selectioncontroller.cpp
+++ b/src/niepce/ui/selectioncontroller.cpp
@@ -203,10 +203,10 @@ bool SelectionController::_set_metadata(const std::string & undo_label,
     auto file_id = engine_db_libfile_id(file.get());
     undo->new_command<void>(
         [libclient, file_id, meta, new_value] () {
-            libclient->setMetadata(file_id, meta, fwk::PropertyValue(new_value));
+            libclient->setMetadata(file_id, meta, fwk::property_value_new(new_value));
         },
         [libclient, file_id, meta, old_value] () {
-            libclient->setMetadata(file_id, meta, fwk::PropertyValue(old_value));
+            libclient->setMetadata(file_id, meta, fwk::property_value_new(old_value));
         });
     undo->execute();
     return true;
@@ -214,26 +214,28 @@ bool SelectionController::_set_metadata(const std::string & undo_label,
 
 bool SelectionController::_set_metadata(const std::string & undo_label,
                                         const eng::LibFilePtr& file,
-                                        const fwk::PropertyBag & props,
-                                        const fwk::PropertyBag & old)
+                                        const fwk::PropertyBagPtr & props,
+                                        const fwk::PropertyBagPtr & old)
 {
     auto undo = fwk::Application::app()->begin_undo(undo_label);
-    for(auto iter : props) {
-        fwk::PropertyValue value;
-        auto result = old.get_value_for_property(iter.first);
-
+    auto len = fwk_property_bag_len(props.get());
+    for (size_t i = 0; i < len; i++) {
+        auto key = fwk_property_bag_key_by_index(props.get(), i);
+        fwk::PropertyValuePtr value = fwk::property_bag_value(old, key);
+        /*
         if (!result.empty()) {
             value = result.unwrap();
-            if(value.get_variant().type() != typeid(fwk::EmptyValue)) {
-                DBG_ASSERT(value.get_variant().type() == iter.second.get_variant().type(),
-                           "Value type mismatch");
+            if (!fwk_property_value_is_empty(value.get())) {
+                // XXX
+                //DBG_ASSERT(value.get_variant().type() == iter.second.get_variant().type(),
+                //           "Value type mismatch");
             }
         }
+        */
 
         auto libclient = getLibraryClient();
         auto file_id = engine_db_libfile_id(file.get());
-        auto key = iter.first;
-        auto new_value = iter.second;
+        auto new_value = fwk::property_bag_value(props, key);
         undo->new_command<void>(
             [libclient, file_id, key, new_value] () {
                 libclient->setMetadata(file_id, key, new_value);
@@ -295,8 +297,8 @@ void SelectionController::set_property(fwk::PropertyIndex idx, int value)
     }
 }
 
-void SelectionController::set_properties(const fwk::PropertyBag & props,
-                                         const fwk::PropertyBag & old)
+void SelectionController::set_properties(const fwk::PropertyBagPtr & props,
+                                         const fwk::PropertyBagPtr & old)
 {
     eng::library_id_t selection = get_selection();
     if(selection >= 0) {
diff --git a/src/niepce/ui/selectioncontroller.hpp b/src/niepce/ui/selectioncontroller.hpp
index 4fa8977..c7db910 100644
--- a/src/niepce/ui/selectioncontroller.hpp
+++ b/src/niepce/ui/selectioncontroller.hpp
@@ -98,8 +98,8 @@ public:
 
     void set_property(fwk::PropertyIndex idx, int value);
 
-    void set_properties(const fwk::PropertyBag & props,
-                        const fwk::PropertyBag & old);
+    void set_properties(const fwk::PropertyBagPtr & props,
+                        const fwk::PropertyBagPtr & old);
 
     /** Write the file(s) metadata to disk. */
     void write_metadata();
@@ -121,8 +121,8 @@ private:
                        int old_value, int new_value);
     bool _set_metadata(const std::string & undo_label,
                        const eng::LibFilePtr& file,
-                       const fwk::PropertyBag & props,
-                       const fwk::PropertyBag & old);
+                       const fwk::PropertyBagPtr & props,
+                       const fwk::PropertyBagPtr & old);
     /** move the selection and emit the signal
      * @param backwards true if the move is backwards.
      */
diff --git a/src/niepce/ui/workspacecontroller.cpp b/src/niepce/ui/workspacecontroller.cpp
index a6d637e..aa8a9e4 100644
--- a/src/niepce/ui/workspacecontroller.cpp
+++ b/src/niepce/ui/workspacecontroller.cpp
@@ -84,7 +84,7 @@ fwk::Configuration::Ptr WorkspaceController::getLibraryConfig() const
 void WorkspaceController::on_lib_notification(const eng::LibNotification &ln)
 {
     DBG_OUT("notification for workspace");
-    switch(engine_library_notification_type(&ln)) {
+    switch(static_cast<eng::LibNotificationType>(engine_library_notification_type(&ln))) {
     case eng::LibNotificationType::ADDED_FOLDER:
     {
         auto f = engine_library_notification_get_libfolder(&ln);
@@ -222,7 +222,7 @@ void WorkspaceController::add_folder_item(const eng::LibFolder* f)
     bool was_empty = children.empty();
     auto iter = add_item(m_treestore, children,
                          m_icons[icon_idx],
-                         engine_db_libfolder_name(f),
+                         engine_db_libfolder_name(const_cast<eng::LibFolder*>(f)),
                          engine_db_libfolder_id(f), FOLDER_ITEM);
     if(engine_db_libfolder_expanded(f)) {
         m_librarytree.expand_row(m_treestore->get_path(iter), false);
diff --git a/src/rust_bindings.hpp b/src/rust_bindings.hpp
new file mode 100644
index 0000000..f68c5b2
--- /dev/null
+++ b/src/rust_bindings.hpp
@@ -0,0 +1,50 @@
+/*
+ * niepce - rust_bindings.hpp
+ *
+ * Copyright (C) 2017 Hubert Figuiere
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#if !RUST_BINDGEN
+
+namespace eng {
+class QueriedContent;
+}
+
+using eng::QueriedContent;
+
+#include "target/bindings.h"
+
+namespace fwk {
+
+typedef ffi::PropertyValue PropertyValue;
+typedef ffi::PropertyBag PropertyBag;
+typedef ffi::Date Date;
+
+}
+
+namespace eng {
+
+typedef ffi::Keyword Keyword;
+typedef ffi::LibFolder LibFolder;
+typedef ffi::LibMetadata LibMetadata;
+typedef ffi::Label Label;
+typedef ffi::Notification LibNotification;
+
+}
+
+#endif



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