From ae6682bc01db0e0febe1fa0c54c5e3ac62188f50 Mon Sep 17 00:00:00 2001
From: Kubat <mael.martin31@gmail.com>
Date: Tue, 11 Oct 2022 22:31:42 +0200
Subject: [PATCH] RUST-DB: Expose creation and deletion symbols as C symbols

---
 CMakeLists.txt                                |  1 +
 src/main/server.c                             |  2 +
 .../liblektor-rs/inc/liblektor-rs/database.h  | 18 ++++++++
 src/rust/liblektor-rs/src/database/mod.rs     |  3 ++
 src/rust/liblektor-rs/src/database/models.rs  |  2 +
 .../src/database/unsafe_interface.rs          | 43 +++++++++++++++++++
 6 files changed, 69 insertions(+)
 create mode 100644 src/rust/liblektor-rs/inc/liblektor-rs/database.h
 create mode 100644 src/rust/liblektor-rs/src/database/unsafe_interface.rs

diff --git a/CMakeLists.txt b/CMakeLists.txt
index e09acd20..42ff35c6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -305,6 +305,7 @@ endif()
 target_include_directories(lkt     PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/inc)
 target_include_directories(lektord PRIVATE
     ${CMAKE_CURRENT_SOURCE_DIR}/inc
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/rust/liblektor-rs/inc
     ${CURL_INCLUDE_DIRS}
 )
 
diff --git a/src/main/server.c b/src/main/server.c
index 7d9225c1..e36d2925 100644
--- a/src/main/server.c
+++ b/src/main/server.c
@@ -9,6 +9,8 @@
 #include <lektor/launch.h>
 #include <lektor/logfile.h>
 
+#include <liblektor-rs/database.h>
+
 #include <wait.h>
 #include <spawn.h>
 #include <libgen.h>
diff --git a/src/rust/liblektor-rs/inc/liblektor-rs/database.h b/src/rust/liblektor-rs/inc/liblektor-rs/database.h
new file mode 100644
index 00000000..b398c88f
--- /dev/null
+++ b/src/rust/liblektor-rs/inc/liblektor-rs/database.h
@@ -0,0 +1,18 @@
+#if !defined(LIBLEKTOR_RS_DATABASE___)
+#define LIBLEKTOR_RS_DATABASE___
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct lkt_sqlite_connection;
+typedef struct lkt_sqlite_connection lkt_sqlite_connection;
+
+lkt_sqlite_connection *lkt_database_establish_connection(const char *);
+void lkt_database_close_connection(lkt_sqlite_connection *const);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // LIBLEKTOR_RS_DATABASE___
diff --git a/src/rust/liblektor-rs/src/database/mod.rs b/src/rust/liblektor-rs/src/database/mod.rs
index bf76fec2..ec02d326 100644
--- a/src/rust/liblektor-rs/src/database/mod.rs
+++ b/src/rust/liblektor-rs/src/database/mod.rs
@@ -1,9 +1,12 @@
+//! Database implementation in rust for lektor.
+
 pub(self) use diesel::prelude::*;
 use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
 pub(self) use log::*;
 
 pub mod models;
 pub mod schema;
+pub mod unsafe_interface;
 
 /// The migrations!
 const MIGRATIONS: EmbeddedMigrations = embed_migrations!();
diff --git a/src/rust/liblektor-rs/src/database/models.rs b/src/rust/liblektor-rs/src/database/models.rs
index d6727d48..a56d6092 100644
--- a/src/rust/liblektor-rs/src/database/models.rs
+++ b/src/rust/liblektor-rs/src/database/models.rs
@@ -1,3 +1,5 @@
+//! Models used for querying, inserting or updating the database.
+
 use crate::database::{schema::*, *};
 
 #[derive(Insertable)]
diff --git a/src/rust/liblektor-rs/src/database/unsafe_interface.rs b/src/rust/liblektor-rs/src/database/unsafe_interface.rs
new file mode 100644
index 00000000..3f79a1fd
--- /dev/null
+++ b/src/rust/liblektor-rs/src/database/unsafe_interface.rs
@@ -0,0 +1,43 @@
+//! An unsafe interface around the rust implementation of the databse to be able
+//! to call it from C or C++ code.
+//!
+//! Be carefull when naming things because those names might collide with things
+//! defined in lektor's C code...
+
+use super::*;
+use std::mem::ManuallyDrop;
+
+/// Wrap the [`establish_connection`] function. On error log the message and
+/// return a [`std::ptr::null_mut`].
+#[no_mangle]
+pub unsafe extern "C" fn lkt_database_establish_connection(
+    path: *const u8,
+) -> *mut SqliteConnection {
+    let mut path_len = 0;
+    while *path.offset(path_len) != 0 {
+        path_len += 1
+    }
+    let len = path_len as usize;
+    let path = ManuallyDrop::new(String::from_raw_parts(path as *mut _, len, len));
+    match establish_connection(&path[..]) {
+        Ok(conn) => Box::leak(Box::new(conn)) as *mut _,
+        Err(err) => {
+            error!("failed to establish connexion to {}: {err}", &path[..]);
+            std::ptr::null_mut()
+        }
+    }
+}
+
+/// Free a database created by [`lkt_database_establish_connection`]. If a null
+/// pointer is passed to the function log the error and do nothing. If the
+/// passed pointer was not obtained by the correct function the behaviour is
+/// undefined.
+#[no_mangle]
+pub unsafe extern "C" fn lkt_database_close_connection(db: *mut SqliteConnection) {
+    if db == std::ptr::null_mut() {
+        error!("can't clost a connexion to a null database!")
+    } else {
+        let db = Box::from_raw(db);
+        drop(db);
+    }
+}
-- 
GitLab