use crate::cxx::ffi; use std::fmt; /// Safe Rust wrapper for VerseKey with proper memory management pub struct VerseKey { ptr: *mut ffi::VerseKey, } impl VerseKey { /// Create a new VerseKey pub fn new() -> Self { let ptr = ffi::new_verse_key(); if ptr.is_null() { panic!("Failed to create VerseKey"); } Self { ptr } } /// Create a new VerseKey from text pub fn from_text(text: &str) -> Self { let ptr = ffi::new_verse_key_from_text(text.to_string()); if ptr.is_null() { panic!("Failed to create VerseKey from text"); } Self { ptr } } /// Create from a raw pointer (for internal use) pub(crate) fn from_raw_ptr(ptr: *mut ffi::VerseKey) -> Self { if ptr.is_null() { panic!("Cannot create VerseKey from null pointer"); } Self { ptr } } /// Get a reference to the underlying VerseKey fn as_ref(&self) -> &ffi::VerseKey { unsafe { &*self.ptr } } /// Get a pinned mutable reference to the underlying VerseKey fn as_pin_mut(&mut self) -> std::pin::Pin<&mut ffi::VerseKey> { unsafe { std::pin::Pin::new_unchecked(&mut *self.ptr) } } /// Check if the VerseKey is valid pub fn is_valid(&self) -> bool { !self.ptr.is_null() && self.as_ref().is_valid() } // Read-only methods pub fn get_error(&self) -> u8 { self.as_ref().get_error() } pub fn get_locale(&self) -> String { self.as_ref().get_locale() } pub fn get_range_text(&self) -> String { self.as_ref().get_range_text() } pub fn get_short_text(&self) -> String { self.as_ref().get_short_text() } pub fn get_text(&self) -> String { self.as_ref().get_text() } pub fn get_book_name(&self) -> String { self.as_ref().get_book_name() } pub fn get_book_abbrev(&self) -> String { self.as_ref().get_book_abbrev() } pub fn get_osis_book_name(&self) -> String { self.as_ref().get_osis_book_name() } pub fn get_osis_ref(&self) -> String { self.as_ref().get_osis_ref() } pub fn get_osis_ref_range_text(&self) -> String { self.as_ref().get_osis_ref_range_text() } pub fn get_short_range_text(&self) -> String { self.as_ref().get_short_range_text() } pub fn get_testament(&self) -> u8 { self.as_ref().get_testament() } pub fn get_testament_max(&self) -> u8 { self.as_ref().get_testament_max() } pub fn get_book(&self) -> u8 { self.as_ref().get_book() } pub fn get_book_max(&self) -> u8 { self.as_ref().get_book_max() } pub fn get_chapter(&self) -> u8 { self.as_ref().get_chapter() } pub fn get_chapter_max(&self) -> u8 { self.as_ref().get_chapter_max() } pub fn get_verse(&self) -> u8 { self.as_ref().get_verse() } pub fn get_verse_max(&self) -> u8 { self.as_ref().get_verse_max() } pub fn is_autonormalize(&self) -> bool { self.as_ref().is_autonormalize() } pub fn is_intros(&self) -> bool { self.as_ref().is_intros() } // Mutable methods pub fn normalize(&mut self, autocheck: bool) { self.as_pin_mut().normalize(autocheck) } pub fn pop_error(&mut self) -> u8 { self.as_pin_mut().pop_error() } pub fn set_locale(&mut self, locale: &str) { self.as_pin_mut().set_locale(&locale.to_string()) } pub fn set_text(&mut self, text: &str) { self.as_pin_mut().set_text(&text.to_string()) } pub fn set_autonormalize(&mut self, auto_normalize: bool) { self.as_pin_mut().set_autonormalize(auto_normalize) } pub fn set_book_name(&mut self, book_name: &str) { self.as_pin_mut().set_book_name(&book_name.to_string()) } pub fn set_intros(&mut self, intros: bool) { self.as_pin_mut().set_intros(intros) } pub fn set_testament(&mut self, testament: u8) { self.as_pin_mut().set_testament(testament) } pub fn set_book(&mut self, book: u8) { self.as_pin_mut().set_book(book) } pub fn set_chapter(&mut self, chapter: u8) { self.as_pin_mut().set_chapter(chapter) } pub fn set_verse(&mut self, verse: u8) { self.as_pin_mut().set_verse(verse) } } impl Default for VerseKey { fn default() -> Self { Self::new() } } impl Clone for VerseKey { fn clone(&self) -> Self { let cloned_ptr = ffi::clone_verse_key(self.as_ref()); if cloned_ptr.is_null() { panic!("Failed to clone VerseKey"); } Self { ptr: cloned_ptr } } } impl Drop for VerseKey { fn drop(&mut self) { if !self.ptr.is_null() { unsafe { ffi::delete_verse_key(self.ptr); } } } } impl fmt::Debug for VerseKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.is_valid() { f.debug_struct("VerseKey") .field("text", &self.get_text()) .field("osis_ref", &self.get_osis_ref()) .finish() } else { f.debug_struct("VerseKey").field("valid", &false).finish() } } } impl fmt::Display for VerseKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.is_valid() { write!(f, "{}", self.get_text()) } else { write!(f, "") } } } unsafe impl Send for VerseKey {} unsafe impl Sync for VerseKey {}