Better wrapping with Rust

Trying to hide most of the CXX nastiness behind the actual module
Move the CXX ffi stuff to its own module
Separate mgr and module mods
Modify main.rs to use the basic code we have done so far
This commit is contained in:
Greg Hellings
2025-02-24 23:18:38 -06:00
parent 87fde0db10
commit 0c3e46497c
6 changed files with 121 additions and 68 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ use system_deps;
fn main() {
let deps = system_deps::Config::new().probe().unwrap();
cxx_build::bridge("src/mgr.rs")
cxx_build::bridge("src/cxx/mod.rs")
.file("src/cxx/mgr.cc")
.includes(deps.all_include_paths())
.cpp_link_stdlib("stdc++")
+70
View File
@@ -0,0 +1,70 @@
#[cxx::bridge]
pub mod ffi {
unsafe extern "C++" {
include!("sword_rs/src/cxx/mgr.h");
include!("sword_rs/src/cxx/module.h");
type Mgr;
type Module;
fn new_mgr() -> UniquePtr<Mgr>;
fn new_mgr_with_path(path: &String) -> UniquePtr<Mgr>;
fn get_modules(self: &Mgr) -> Vec<String>;
fn get_module(self: Pin<&mut Mgr>, name: &String) -> UniquePtr<Module>;
fn get_name(self: &Module) -> String;
fn strip_text(self: Pin<&mut Module>) -> String;
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::{create_dir, File};
use std::io::Write;
use tempfile;
#[test]
fn can_create_mgr() {
let mgr = ffi::new_mgr();
assert!(!mgr.is_null());
}
#[test]
fn reads_module_list() {
// Create a temporary directory to isolate tests
let dir = tempfile::tempdir().unwrap();
// Create a basic SWORD directory
let mods_d = dir.path().join("mods.d");
create_dir(&mods_d).unwrap();
// Write a dummy conf file
let kjv_conf = mods_d.join("kjv.conf");
{
let mut file = File::create(&kjv_conf).unwrap();
writeln!(file, "[KJVdummy]").unwrap();
writeln!(file, "DataPath=./modules/texts/ztext/kjv").unwrap();
writeln!(file, "ModDrv=RawText").unwrap();
writeln!(file, "Description=Test description").unwrap();
writeln!(file, "About=A test conf file").unwrap();
}
let mut mgr = ffi::new_mgr_with_path(&dir.path().to_str().unwrap().to_string());
assert!(mgr.get_modules().len() == 1);
assert!(mgr.get_modules().contains(&String::from("KJVdummy")));
let mut module = mgr.pin_mut().get_module(&String::from("KJVdummy"));
assert!(module.pin_mut().get_name() == "KJVdummy");
}
#[test]
fn has_no_modules() {
let mgr = ffi::new_mgr_with_path(
&tempfile::tempdir()
.unwrap()
.path()
.to_str()
.unwrap()
.to_string(),
);
assert!(mgr.get_modules().len() == 0);
}
}
+2
View File
@@ -1 +1,3 @@
mod cxx;
pub mod mgr;
mod module;
+7 -3
View File
@@ -1,6 +1,10 @@
use sword_rs::mgr::{new_mgr, Mgr};
use sword_rs::mgr::Mgr;
fn main() {
let mgr = new_mgr();
println!("{:?}", mgr.get_modules());
let mut mgr = Mgr::new();
for mod_name in mgr.get_modules() {
let mut module = mgr.get_module(&mod_name);
println!("Module: {}", module.get_name());
println!("Text: {}", module.strip_text());
}
}
+21 -64
View File
@@ -1,72 +1,29 @@
pub use ffi::*;
use crate::cxx::ffi;
use crate::module::Module;
use cxx::UniquePtr;
#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
include!("sword_rs/src/cxx/mgr.h");
include!("sword_rs/src/cxx/module.h");
type Mgr;
type Module;
fn new_mgr() -> UniquePtr<Mgr>;
fn new_mgr_with_path(path: &String) -> UniquePtr<Mgr>;
fn get_modules(self: &Mgr) -> Vec<String>;
fn get_module(self: Pin<&mut Mgr>, name: &String) -> UniquePtr<Module>;
fn get_name(self: &Module) -> String;
fn strip_text(self: Pin<&mut Module>) -> String;
}
pub struct Mgr {
mgr: UniquePtr<ffi::Mgr>,
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::{create_dir, File};
use std::io::Write;
use tempfile;
#[test]
fn can_create_mgr() {
let mgr = ffi::new_mgr();
assert!(!mgr.is_null());
}
#[test]
fn reads_module_list() {
// Create a temporary directory to isolate tests
let dir = tempfile::tempdir().unwrap();
// Create a basic SWORD directory
let mods_d = dir.path().join("mods.d");
create_dir(&mods_d).unwrap();
// Write a dummy conf file
let kjv_conf = mods_d.join("kjv.conf");
{
let mut file = File::create(&kjv_conf).unwrap();
writeln!(file, "[KJVdummy]").unwrap();
writeln!(file, "DataPath=./modules/texts/ztext/kjv").unwrap();
writeln!(file, "ModDrv=RawText").unwrap();
writeln!(file, "Description=Test description").unwrap();
writeln!(file, "About=A test conf file").unwrap();
impl Mgr {
pub fn new() -> Self {
Self {
mgr: ffi::new_mgr(),
}
let mut mgr = ffi::new_mgr_with_path(&dir.path().to_str().unwrap().to_string());
assert!(mgr.get_modules().len() == 1);
assert!(mgr.get_modules().contains(&String::from("KJVdummy")));
let mut module = mgr.pin_mut().get_module(&String::from("KJVdummy"));
assert!(module.pin_mut().get_name() == "KJVdummy");
}
#[test]
fn has_no_modules() {
let mgr = ffi::new_mgr_with_path(
&tempfile::tempdir()
.unwrap()
.path()
.to_str()
.unwrap()
.to_string(),
);
assert!(mgr.get_modules().len() == 0);
pub fn new_with_path(path: &String) -> Self {
Self {
mgr: ffi::new_mgr_with_path(path),
}
}
pub fn get_modules(&self) -> Vec<String> {
self.mgr.get_modules()
}
pub fn get_module(&mut self, mod_name: &String) -> Module {
Module::new(self.mgr.pin_mut().get_module(mod_name))
}
}
+20
View File
@@ -0,0 +1,20 @@
use crate::cxx::ffi;
use cxx::UniquePtr;
pub struct Module {
module: UniquePtr<ffi::Module>,
}
impl Module {
pub fn new(module: UniquePtr<ffi::Module>) -> Self {
Self { module: module }
}
pub fn get_name(&self) -> String {
self.module.get_name()
}
pub fn strip_text(&mut self) -> String {
self.module.pin_mut().strip_text()
}
}