With a little help, we now have VerseKey

Went with a basic wrapper that cxx is able to handle for the bridge
between the languages, along with simple wrapper methods
This commit is contained in:
Greg Hellings
2025-06-25 02:30:42 -05:00
parent fc7b3a7ec5
commit c8dd1ce0f0
12 changed files with 919 additions and 10 deletions
+8 -10
View File
@@ -1,23 +1,21 @@
use system_deps;
fn main() {
let sources = vec!["key", "mgr", "module", "versekey", "versification"];
let deps = system_deps::Config::new().probe().unwrap();
cxx_build::bridge("src/cxx/mod.rs")
.file("src/cxx/mgr.cc")
.file("src/cxx/module.cc")
.file("src/cxx/versification.cc")
let mut build = cxx_build::bridge("src/cxx/mod.rs");
for src in sources {
build.file(&format!("src/cxx/{}.cc", src));
println!("cargo:rerun-if-changed=src/cxx/{}.cc", src);
println!("cargo:rerun-if-changed=src/cxx/{}.h", src);
}
build
.includes(deps.all_include_paths())
.cpp_link_stdlib("stdc++")
.flag("-Os")
.compile("sword_rs");
println!("cargo:rerun-if-changed=src/cxx/mod.rs");
println!("cargo:rerun-if-changed=src/cxx/mgr.cc");
println!("cargo:rerun-if-changed=src/cxx/mgr.h");
println!("cargo:rerun-if-changed=src/cxx/module.cc");
println!("cargo:rerun-if-changed=src/cxx/module.h");
println!("cargo:rerun-if-changed=src/cxx/versification.h");
println!("cargo:rerun-if-changed=src/cxx/versification.cc");
println!("cargo:rustc-link-lib=sword");
}
+35
View File
@@ -0,0 +1,35 @@
#include "key.h"
namespace sword_rs {
uint8_t Key::get_error() const {
return this->getError();
}
rust::String Key::get_locale() const {
return rust::String(this->getLocale());
}
rust::String Key::get_range_text() const {
return rust::String(this->getRangeText());
}
rust::String Key::get_short_text() const {
return rust::String(this->getShortText());
}
rust::String Key::get_text() const {
return rust::String(this->getText());
}
uint8_t Key::pop_error() {
return this->popError();
}
void Key::set_locale(const rust::String &locale) {
this->setLocale(std::string(locale).c_str());
}
void Key::set_text(const rust::String &text) {
this->setText(std::string(text).c_str());
}
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <sword/swkey.h>
#include "rust/cxx.h"
namespace sword_rs {
class Key : public sword::SWKey {
public:
uint8_t get_error() const;
rust::String get_locale() const;
rust::String get_range_text() const;
rust::String get_short_text() const;
rust::String get_text() const;
uint8_t pop_error();
void set_locale(const rust::String &locale);
void set_text(const rust::String &text);
};
}
+160
View File
@@ -4,6 +4,7 @@ pub mod ffi {
include!("sword_rs/src/cxx/mgr.h");
include!("sword_rs/src/cxx/module.h");
include!("sword_rs/src/cxx/versification.h");
include!("sword_rs/src/cxx/versekey.h");
type Mgr;
@@ -18,6 +19,7 @@ pub mod ffi {
fn decrement(self: Pin<&mut Module>);
fn get_name(self: &Module) -> String;
fn get_type(self: &Module) -> String;
fn get_verse_key(self: &Module) -> *mut VerseKey;
fn increment(self: Pin<&mut Module>);
fn is_skip_consecutive_links(self: &Module) -> bool;
fn render_text(self: Pin<&mut Module>) -> String;
@@ -31,6 +33,56 @@ pub mod ffi {
fn getVersifications(self: &Versification) -> Vec<String>;
fn getVersification(self: &Versification, name: &mut String) -> *const VersificationSystem;
fn new_versification() -> UniquePtr<Versification>;
type VerseKey;
// Factory functions for VerseKey
fn new_verse_key() -> UniquePtr<VerseKey>;
fn new_verse_key_from_text(text: &String) -> UniquePtr<VerseKey>;
unsafe fn delete_verse_key(key: *mut VerseKey);
// From Key
fn get_error(self: &VerseKey) -> u8;
fn get_locale(self: &VerseKey) -> String;
fn get_range_text(self: &VerseKey) -> String;
fn get_short_text(self: &VerseKey) -> String;
fn get_text(self: &VerseKey) -> String;
fn normalize(self: Pin<&mut VerseKey>, autocheck: bool);
// From VerseKey
fn get_book_name(self: &VerseKey) -> String;
fn get_book_abbrev(self: &VerseKey) -> String;
fn get_osis_book_name(self: &VerseKey) -> String;
fn get_osis_ref(self: &VerseKey) -> String;
fn get_osis_ref_range_text(self: &VerseKey) -> String;
fn get_short_range_text(self: &VerseKey) -> String;
fn get_testament(self: &VerseKey) -> u8;
fn get_testament_max(self: &VerseKey) -> u8;
fn get_book(self: &VerseKey) -> u8;
fn get_book_max(self: &VerseKey) -> u8;
fn get_chapter(self: &VerseKey) -> u8;
fn get_chapter_max(self: &VerseKey) -> u8;
fn get_verse(self: &VerseKey) -> u8;
fn get_verse_max(self: &VerseKey) -> u8;
// From VerseKey
fn is_autonormalize(self: &VerseKey) -> bool;
fn is_intros(self: &VerseKey) -> bool;
// From Key
fn pop_error(self: Pin<&mut VerseKey>) -> u8;
// From Key
fn set_locale(self: Pin<&mut VerseKey>, locale: &String);
fn set_text(self: Pin<&mut VerseKey>, text: &String);
// From VerseKey
fn set_autonormalize(self: Pin<&mut VerseKey>, autoNormalize: bool);
fn set_book_name(self: Pin<&mut VerseKey>, bookName: &String);
fn set_intros(self: Pin<&mut VerseKey>, intros: bool);
fn set_testament(self: Pin<&mut VerseKey>, testament: u8);
fn set_book(self: Pin<&mut VerseKey>, book: u8);
fn set_chapter(self: Pin<&mut VerseKey>, chapter: u8);
fn set_verse(self: Pin<&mut VerseKey>, verse: u8);
// Explicit cleanup
fn cleanup(self: Pin<&mut VerseKey>);
}
}
@@ -92,4 +144,112 @@ mod tests {
);
assert!(mgr.get_modules().len() == 0);
}
#[test]
fn can_create_verse_key() {
let verse_key = ffi::new_verse_key();
assert!(!verse_key.is_null());
// Test that we can call methods without errors
let _testament = verse_key.get_testament();
let _book = verse_key.get_book();
let _chapter = verse_key.get_chapter();
let _verse = verse_key.get_verse();
let _book_name = verse_key.get_book_name();
let _text = verse_key.get_text();
}
#[test]
fn can_create_verse_key_from_text() {
let verse_key = ffi::new_verse_key_from_text(&"Genesis 1:1".to_string());
assert!(!verse_key.is_null());
// Test that we can get values without errors
let _chapter = verse_key.get_chapter();
let _verse = verse_key.get_verse();
let _text = verse_key.get_text();
}
#[test]
fn verse_key_can_be_modified() {
let mut verse_key = ffi::new_verse_key();
// Test that we can call setter methods without panicking
verse_key.pin_mut().set_chapter(5);
verse_key.pin_mut().set_verse(10);
verse_key.pin_mut().set_text(&"Genesis 1:1".to_string());
// Test that we can call getter methods after setting
let _chapter = verse_key.get_chapter();
let _verse = verse_key.get_verse();
let _text = verse_key.get_text();
}
#[test]
fn high_level_verse_key_api() {
use crate::versekey::VerseKey;
// Test owned VerseKey creation and usage
let mut verse_key = VerseKey::new();
// Test that we can call methods without panicking
verse_key.set_chapter(3);
verse_key.set_verse(16);
verse_key.set_text("John 3:16");
// Test getters
let _book_name = verse_key.get_book_name();
let _text = verse_key.get_text();
let _chapter = verse_key.get_chapter();
let _verse = verse_key.get_verse();
// Test creation from text
let verse_key2 = VerseKey::from_text("Romans 8:28");
let _text2 = verse_key2.get_text();
}
#[test]
fn borrowed_verse_key_from_module() {
use std::fs::{create_dir, File};
use std::io::Write;
use tempfile;
// Create a temporary directory with a module
let dir = tempfile::tempdir().unwrap();
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();
}
// Create manager and get module
let mut mgr = ffi::new_mgr_with_path(&dir.path().to_str().unwrap().to_string());
let mut module = mgr.pin_mut().get_module(&String::from("KJVdummy"));
// Test that we can get a VerseKey from the module
let verse_key_ptr = module.pin_mut().get_verse_key();
if !verse_key_ptr.is_null() {
// Test that we can create a BorrowedVerseKey and use it
let borrowed_verse_key =
unsafe { crate::versekey::BorrowedVerseKey::from_ptr(verse_key_ptr) };
if let Some(mut borrowed_vk) = borrowed_verse_key {
// Test that we can call methods without panicking
let _book_name = borrowed_vk.get_book_name();
let _text = borrowed_vk.get_text();
borrowed_vk.set_chapter(1);
borrowed_vk.set_verse(1);
let _chapter = borrowed_vk.get_chapter();
let _verse = borrowed_vk.get_verse();
}
}
}
}
+10
View File
@@ -15,6 +15,16 @@ namespace sword_rs {
return rust::String(this->module->getType());
}
VerseKey* Module::get_verse_key() const {
sword::VerseKey* key = dynamic_cast<sword::VerseKey*>(this->module->getKey());
if (key) {
// Create a borrowed VerseKey on the heap - caller must delete but not the inner ptr
VerseKey* result = new VerseKey{key, false};
return result;
}
return nullptr;
}
void Module::increment() {
this->module->increment();
}
+4
View File
@@ -1,9 +1,11 @@
#pragma once
#include <memory>
#include <sword/swmodule.h>
#include <string>
#include "rust/cxx.h"
#include "versekey.h"
namespace sword_rs {
class Module {
@@ -19,6 +21,8 @@ namespace sword_rs {
rust::String get_type() const;
VerseKey* get_verse_key() const;
void increment();
bool is_skip_consecutive_links() const;
+187
View File
@@ -0,0 +1,187 @@
#include "versekey.h"
#include <memory>
#include <sword/versekey.h>
namespace sword_rs {
// Key methods
uint8_t VerseKey::get_error() const {
return ptr ? ptr->getError() : 0;
}
rust::String VerseKey::get_locale() const {
return ptr ? rust::String(ptr->getLocale()) : rust::String("");
}
rust::String VerseKey::get_range_text() const {
return ptr ? rust::String(ptr->getRangeText()) : rust::String("");
}
rust::String VerseKey::get_short_text() const {
return ptr ? rust::String(ptr->getShortText()) : rust::String("");
}
rust::String VerseKey::get_text() const {
return ptr ? rust::String(ptr->getText()) : rust::String("");
}
void VerseKey::normalize(bool autocheck) {
if (ptr) {
ptr->normalize(autocheck);
}
}
uint8_t VerseKey::pop_error() {
return ptr ? ptr->popError() : 0;
}
void VerseKey::set_locale(const rust::String &locale) {
if (ptr) {
ptr->setLocale(std::string(locale).c_str());
}
}
void VerseKey::set_text(const rust::String &text) {
if (ptr) {
ptr->setText(std::string(text).c_str());
}
}
// VerseKey specific methods
rust::String VerseKey::get_book_name() const {
return ptr ? rust::String(ptr->getBookName()) : rust::String("");
}
rust::String VerseKey::get_book_abbrev() const {
return ptr ? rust::String(ptr->getBookAbbrev()) : rust::String("");
}
rust::String VerseKey::get_osis_book_name() const {
return ptr ? rust::String(ptr->getOSISBookName()) : rust::String("");
}
rust::String VerseKey::get_osis_ref() const {
return ptr ? rust::String(ptr->getOSISRef()) : rust::String("");
}
rust::String VerseKey::get_osis_ref_range_text() const {
return ptr ? rust::String(ptr->getOSISRefRangeText()) : rust::String("");
}
rust::String VerseKey::get_short_range_text() const {
return ptr ? rust::String(ptr->getShortRangeText()) : rust::String("");
}
uint8_t VerseKey::get_testament() const {
return ptr ? ptr->getTestament() : 0;
}
uint8_t VerseKey::get_testament_max() const {
return ptr ? ptr->getTestamentMax() : 0;
}
uint8_t VerseKey::get_book() const {
return ptr ? ptr->getBook() : 0;
}
uint8_t VerseKey::get_book_max() const {
return ptr ? ptr->getBookMax() : 0;
}
uint8_t VerseKey::get_chapter() const {
return ptr ? ptr->getChapter() : 0;
}
uint8_t VerseKey::get_chapter_max() const {
return ptr ? ptr->getChapterMax() : 0;
}
uint8_t VerseKey::get_verse() const {
return ptr ? ptr->getVerse() : 0;
}
uint8_t VerseKey::get_verse_max() const {
return ptr ? ptr->getVerseMax() : 0;
}
bool VerseKey::is_autonormalize() const {
return ptr ? ptr->isAutoNormalize() : false;
}
bool VerseKey::is_intros() const {
return ptr ? ptr->isIntros() : false;
}
void VerseKey::set_autonormalize(bool autoNormalize) {
if (ptr) {
ptr->setAutoNormalize(autoNormalize);
}
}
void VerseKey::set_book_name(const rust::String &bookName) {
if (ptr) {
ptr->setBookName(std::string(bookName).c_str());
}
}
void VerseKey::set_intros(bool intros) {
if (ptr) {
ptr->setIntros(intros);
}
}
void VerseKey::set_testament(uint8_t testament) {
if (ptr) {
ptr->setTestament(testament);
}
}
void VerseKey::set_book(uint8_t book) {
if (ptr) {
ptr->setBook(book);
}
}
void VerseKey::set_chapter(uint8_t chapter) {
if (ptr) {
ptr->setChapter(chapter);
}
}
void VerseKey::set_verse(uint8_t verse) {
if (ptr) {
ptr->setVerse(verse);
}
}
// Explicit cleanup method
void VerseKey::cleanup() {
if (owned && ptr) {
delete ptr;
ptr = nullptr;
owned = false;
}
}
// Factory functions
std::unique_ptr<VerseKey> new_verse_key() {
auto verse_key = std::unique_ptr<VerseKey>(new VerseKey{new sword::VerseKey(), true});
return verse_key;
}
std::unique_ptr<VerseKey> new_verse_key_from_text(const rust::String& text) {
auto verse_key = std::unique_ptr<VerseKey>(new VerseKey{new sword::VerseKey(std::string(text).c_str()), true});
return verse_key;
}
VerseKey verse_key_from_borrowed(sword::VerseKey* key) {
VerseKey verse_key{key, false};
return verse_key;
}
void delete_verse_key(VerseKey* key) {
if (key) {
key->cleanup();
delete key;
}
}
}
+64
View File
@@ -0,0 +1,64 @@
#pragma once
#include <memory>
#include <sword/swkey.h>
#include <sword/versekey.h>
#include "rust/cxx.h"
namespace sword_rs {
// Trivial wrapper that just holds a pointer and ownership flag
// No destructor - cleanup is handled explicitly
struct VerseKey {
sword::VerseKey* ptr;
bool owned;
// Key methods
uint8_t get_error() const;
rust::String get_locale() const;
rust::String get_range_text() const;
rust::String get_short_text() const;
rust::String get_text() const;
void normalize(bool autocheck);
uint8_t pop_error();
void set_locale(const rust::String &locale);
void set_text(const rust::String &text);
// VerseKey methods
rust::String get_book_name() const;
rust::String get_book_abbrev() const;
rust::String get_osis_book_name() const;
rust::String get_osis_ref() const;
rust::String get_osis_ref_range_text() const;
rust::String get_short_range_text() const;
uint8_t get_testament() const;
uint8_t get_testament_max() const;
uint8_t get_book() const;
uint8_t get_book_max() const;
uint8_t get_chapter() const;
uint8_t get_chapter_max() const;
uint8_t get_verse() const;
uint8_t get_verse_max() const;
bool is_autonormalize() const;
bool is_intros() const;
void set_autonormalize(bool autoNormalize);
void set_book_name(const rust::String &bookName);
void set_intros(bool intros);
void set_testament(uint8_t testament);
void set_book(uint8_t book);
void set_chapter(uint8_t chapter);
void set_verse(uint8_t verse);
// Explicit cleanup method
void cleanup();
};
// Factory functions for creating VerseKeys
std::unique_ptr<VerseKey> new_verse_key();
std::unique_ptr<VerseKey> new_verse_key_from_text(const rust::String& text);
VerseKey verse_key_from_borrowed(sword::VerseKey* key);
// Memory management for raw VerseKey pointers
void delete_verse_key(VerseKey* key);
}
+1
View File
@@ -1,3 +1,4 @@
mod cxx;
pub mod mgr;
pub mod module;
pub mod versekey;
+19
View File
@@ -2,6 +2,25 @@ use rand::Rng;
use sword_rs::mgr::{Format, Mgr};
fn main() {
one_chapter();
// iterate();
}
fn one_chapter() {
let mut mgr = Mgr::new_with_format(Format::HTMLHref);
let mut module = mgr.get_module(&String::from("KJV"));
let mut key = module
.get_verse_key()
.expect("This was not a verse based module?!");
key.set_book_name(&String::from("John"));
key.set_chapter(3);
for verse in 1..=key.get_verse_max() {
key.set_verse(verse);
println!("{}: {}", key.get_short_text(), module.render_text());
}
}
fn iterate() {
let mut mgr = Mgr::new_with_format(Format::HTMLHref);
for mod_name in mgr.get_modules() {
let mut module = mgr.get_module(&mod_name);
+12
View File
@@ -83,4 +83,16 @@ impl Module {
pub fn strip_text(&mut self) -> String {
self.module.pin_mut().strip_text()
}
pub fn get_verse_key(&mut self) -> Option<crate::versekey::BorrowedVerseKey> {
match self.get_type() {
Type::BiblicalTexts => unsafe {
crate::versekey::BorrowedVerseKey::from_ptr(self.module.pin_mut().get_verse_key())
},
Type::Commentaries => unsafe {
crate::versekey::BorrowedVerseKey::from_ptr(self.module.pin_mut().get_verse_key())
},
_ => None,
}
}
}
+398
View File
@@ -0,0 +1,398 @@
use crate::cxx::ffi;
/// Safe wrapper for owned VerseKey instances
pub struct VerseKey {
inner: cxx::UniquePtr<ffi::VerseKey>,
}
impl VerseKey {
/// Create a new VerseKey
pub fn new() -> Self {
Self {
inner: ffi::new_verse_key(),
}
}
/// Create a new VerseKey from text
pub fn from_text(text: &str) -> Self {
Self {
inner: ffi::new_verse_key_from_text(&text.to_string()),
}
}
/// Get the book name
pub fn get_book_name(&self) -> String {
self.inner.get_book_name()
}
/// Get the book abbreviation
pub fn get_book_abbrev(&self) -> String {
self.inner.get_book_abbrev()
}
/// Get the OSIS book name
pub fn get_osis_book_name(&self) -> String {
self.inner.get_osis_book_name()
}
/// Get the OSIS reference
pub fn get_osis_ref(&self) -> String {
self.inner.get_osis_ref()
}
/// Get the OSIS reference range text
pub fn get_osis_ref_range_text(&self) -> String {
self.inner.get_osis_ref_range_text()
}
/// Get the short range text
pub fn get_short_range_text(&self) -> String {
self.inner.get_short_range_text()
}
/// Get the testament number
pub fn get_testament(&self) -> u8 {
self.inner.get_testament()
}
/// Get the maximum testament number
pub fn get_testament_max(&self) -> u8 {
self.inner.get_testament_max()
}
/// Get the book number
pub fn get_book(&self) -> u8 {
self.inner.get_book()
}
/// Get the maximum book number
pub fn get_book_max(&self) -> u8 {
self.inner.get_book_max()
}
/// Get the chapter number
pub fn get_chapter(&self) -> u8 {
self.inner.get_chapter()
}
/// Get the maximum chapter number
pub fn get_chapter_max(&self) -> u8 {
self.inner.get_chapter_max()
}
/// Get the verse number
pub fn get_verse(&self) -> u8 {
self.inner.get_verse()
}
/// Get the maximum verse number
pub fn get_verse_max(&self) -> u8 {
self.inner.get_verse_max()
}
/// Check if auto-normalize is enabled
pub fn is_autonormalize(&self) -> bool {
self.inner.is_autonormalize()
}
/// Check if intros are enabled
pub fn is_intros(&self) -> bool {
self.inner.is_intros()
}
/// Get the error code
pub fn get_error(&self) -> u8 {
self.inner.get_error()
}
/// Get the locale
pub fn get_locale(&self) -> String {
self.inner.get_locale()
}
/// Get the range text
pub fn get_range_text(&self) -> String {
self.inner.get_range_text()
}
/// Get the short text
pub fn get_short_text(&self) -> String {
self.inner.get_short_text()
}
/// Get the text
pub fn get_text(&self) -> String {
self.inner.get_text()
}
/// Normalize the key
pub fn normalize(&mut self, autocheck: bool) {
self.inner.pin_mut().normalize(autocheck)
}
/// Pop an error
pub fn pop_error(&mut self) -> u8 {
self.inner.pin_mut().pop_error()
}
/// Set auto-normalize
pub fn set_autonormalize(&mut self, auto_normalize: bool) {
self.inner.pin_mut().set_autonormalize(auto_normalize)
}
/// Set the book name
pub fn set_book_name(&mut self, book_name: &str) {
self.inner.pin_mut().set_book_name(&book_name.to_string())
}
/// Set intros
pub fn set_intros(&mut self, intros: bool) {
self.inner.pin_mut().set_intros(intros)
}
/// Set the locale
pub fn set_locale(&mut self, locale: &str) {
self.inner.pin_mut().set_locale(&locale.to_string())
}
/// Set the text
pub fn set_text(&mut self, text: &str) {
self.inner.pin_mut().set_text(&text.to_string())
}
/// Set the testament
pub fn set_testament(&mut self, testament: u8) {
self.inner.pin_mut().set_testament(testament)
}
/// Set the book
pub fn set_book(&mut self, book: u8) {
self.inner.pin_mut().set_book(book)
}
/// Set the chapter
pub fn set_chapter(&mut self, chapter: u8) {
self.inner.pin_mut().set_chapter(chapter)
}
/// Set the verse
pub fn set_verse(&mut self, verse: u8) {
self.inner.pin_mut().set_verse(verse)
}
}
impl Default for VerseKey {
fn default() -> Self {
Self::new()
}
}
/// Wrapper for borrowed VerseKey instances (from modules)
pub struct BorrowedVerseKey {
ptr: *mut ffi::VerseKey,
}
impl BorrowedVerseKey {
/// Create from a raw pointer (unsafe)
pub unsafe fn from_ptr(ptr: *mut ffi::VerseKey) -> Option<Self> {
if ptr.is_null() {
None
} else {
Some(Self { ptr })
}
}
/// Get the book name
pub fn get_book_name(&self) -> String {
unsafe { (&*self.ptr).get_book_name() }
}
/// Get the book abbreviation
pub fn get_book_abbrev(&self) -> String {
unsafe { (&*self.ptr).get_book_abbrev() }
}
/// Get the OSIS book name
pub fn get_osis_book_name(&self) -> String {
unsafe { (&*self.ptr).get_osis_book_name() }
}
/// Get the OSIS reference
pub fn get_osis_ref(&self) -> String {
unsafe { (&*self.ptr).get_osis_ref() }
}
/// Get the OSIS reference range text
pub fn get_osis_ref_range_text(&self) -> String {
unsafe { (&*self.ptr).get_osis_ref_range_text() }
}
/// Get the short range text
pub fn get_short_range_text(&self) -> String {
unsafe { (&*self.ptr).get_short_range_text() }
}
/// Get the testament number
pub fn get_testament(&self) -> u8 {
unsafe { (&*self.ptr).get_testament() }
}
/// Get the maximum testament number
pub fn get_testament_max(&self) -> u8 {
unsafe { (&*self.ptr).get_testament_max() }
}
/// Get the book number
pub fn get_book(&self) -> u8 {
unsafe { (&*self.ptr).get_book() }
}
/// Get the maximum book number
pub fn get_book_max(&self) -> u8 {
unsafe { (&*self.ptr).get_book_max() }
}
/// Get the chapter number
pub fn get_chapter(&self) -> u8 {
unsafe { (&*self.ptr).get_chapter() }
}
/// Get the maximum chapter number
pub fn get_chapter_max(&self) -> u8 {
unsafe { (&*self.ptr).get_chapter_max() }
}
/// Get the verse number
pub fn get_verse(&self) -> u8 {
unsafe { (&*self.ptr).get_verse() }
}
/// Get the maximum verse number
pub fn get_verse_max(&self) -> u8 {
unsafe { (&*self.ptr).get_verse_max() }
}
/// Check if auto-normalize is enabled
pub fn is_autonormalize(&self) -> bool {
unsafe { (&*self.ptr).is_autonormalize() }
}
/// Check if intros are enabled
pub fn is_intros(&self) -> bool {
unsafe { (&*self.ptr).is_intros() }
}
/// Get the error code
pub fn get_error(&self) -> u8 {
unsafe { (&*self.ptr).get_error() }
}
/// Get the locale
pub fn get_locale(&self) -> String {
unsafe { (&*self.ptr).get_locale() }
}
/// Get the range text
pub fn get_range_text(&self) -> String {
unsafe { (&*self.ptr).get_range_text() }
}
/// Get the short text
pub fn get_short_text(&self) -> String {
unsafe { (&*self.ptr).get_short_text() }
}
/// Get the text
pub fn get_text(&self) -> String {
unsafe { (&*self.ptr).get_text() }
}
/// Normalize the key
pub fn normalize(&mut self, autocheck: bool) {
unsafe {
std::pin::Pin::new_unchecked(&mut *self.ptr).normalize(autocheck);
}
}
/// Pop an error
pub fn pop_error(&mut self) -> u8 {
unsafe { std::pin::Pin::new_unchecked(&mut *self.ptr).pop_error() }
}
/// Set auto-normalize
pub fn set_autonormalize(&mut self, auto_normalize: bool) {
unsafe {
std::pin::Pin::new_unchecked(&mut *self.ptr).set_autonormalize(auto_normalize);
}
}
/// Set the book name
pub fn set_book_name(&mut self, book_name: &str) {
unsafe {
std::pin::Pin::new_unchecked(&mut *self.ptr).set_book_name(&book_name.to_string());
}
}
/// Set intros
pub fn set_intros(&mut self, intros: bool) {
unsafe {
std::pin::Pin::new_unchecked(&mut *self.ptr).set_intros(intros);
}
}
/// Set the locale
pub fn set_locale(&mut self, locale: &str) {
unsafe {
std::pin::Pin::new_unchecked(&mut *self.ptr).set_locale(&locale.to_string());
}
}
/// Set the text
pub fn set_text(&mut self, text: &str) {
unsafe {
std::pin::Pin::new_unchecked(&mut *self.ptr).set_text(&text.to_string());
}
}
/// Set the testament
pub fn set_testament(&mut self, testament: u8) {
unsafe {
std::pin::Pin::new_unchecked(&mut *self.ptr).set_testament(testament);
}
}
/// Set the book
pub fn set_book(&mut self, book: u8) {
unsafe {
std::pin::Pin::new_unchecked(&mut *self.ptr).set_book(book);
}
}
/// Set the chapter
pub fn set_chapter(&mut self, chapter: u8) {
unsafe {
std::pin::Pin::new_unchecked(&mut *self.ptr).set_chapter(chapter);
}
}
/// Set the verse
pub fn set_verse(&mut self, verse: u8) {
unsafe {
std::pin::Pin::new_unchecked(&mut *self.ptr).set_verse(verse);
}
}
}
impl Drop for BorrowedVerseKey {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe {
ffi::delete_verse_key(self.ptr);
}
}
}
}
// Safety: BorrowedVerseKey can be sent between threads safely as long as
// the underlying SWORD library is thread-safe for reading
unsafe impl Send for BorrowedVerseKey {}