haqumei 0.8.0

Haqumei is a Japanese Grapheme-to-Phoneme (G2P) library implemented in Rust.
Documentation
use crate::{errors::HaqumeiError, ffi, open_jtalk::jpcommon_rule::NODATA};

use std::{ffi::c_char, mem::MaybeUninit, ptr::NonNull};

#[derive(Debug)]
pub(crate) struct JpCommon {
    pub(crate) inner: NonNull<ffi::JPCommon>,
}

impl JpCommon {
    pub(crate) fn new() -> Result<Self, HaqumeiError> {
        unsafe {
            let mut jp_common_uninit = Box::new(MaybeUninit::<ffi::JPCommon>::uninit());

            ffi::JPCommon_initialize(jp_common_uninit.as_mut_ptr());

            let jp_common_init = jp_common_uninit.assume_init();

            let raw_ptr = Box::into_raw(jp_common_init);

            match NonNull::new(raw_ptr) {
                Some(inner) => Ok(Self { inner }),
                None => {
                    let _ = Box::from_raw(raw_ptr);
                    Err(HaqumeiError::AllocationError("_JPCommon"))
                }
            }
        }
    }
}

impl Drop for JpCommon {
    fn drop(&mut self) {
        unsafe {
            ffi::JPCommon_clear(self.inner.as_ptr());

            let _ = Box::from_raw(self.inner.as_ptr());
        }
    }
}

pub(crate) trait FreeNode {
    unsafe fn free_node(self);
}

impl FreeNode for *mut ffi::JPCommonLabelPhoneme {
    unsafe fn free_node(self) {
        unsafe {
            if !self.is_null() {
                let s = (*self).phoneme;
                if !s.is_null() && s != NODATA.as_ptr() as *mut c_char {
                    libc::free(s as *mut _);
                }
                libc::free(self as *mut _);
            }
        }
    }
}

impl FreeNode for *mut ffi::JPCommonLabelMora {
    unsafe fn free_node(self) {
        unsafe {
            if !self.is_null() {
                let s = (*self).mora;
                if !s.is_null() && s != NODATA.as_ptr() as *mut c_char {
                    libc::free(s as *mut _);
                }
                libc::free(self as *mut _);
            }
        }
    }
}

impl FreeNode for *mut ffi::JPCommonLabelWord {
    unsafe fn free_node(self) {
        unsafe {
            if !self.is_null() {
                let pron = (*self).pron;
                if !pron.is_null() && pron != NODATA.as_ptr() as *mut c_char {
                    libc::free(pron as *mut _);
                }
                let pos = (*self).pos;
                if !pos.is_null() && pos != NODATA.as_ptr() as *mut c_char {
                    libc::free(pos as *mut _);
                }
                let ctype = (*self).ctype;
                if !ctype.is_null() && ctype != NODATA.as_ptr() as *mut c_char {
                    libc::free(ctype as *mut _);
                }
                let cform = (*self).cform;
                if !cform.is_null() && cform != NODATA.as_ptr() as *mut c_char {
                    libc::free(cform as *mut _);
                }
                libc::free(self as *mut _);
            }
        }
    }
}

impl FreeNode for *mut ffi::JPCommonLabelAccentPhrase {
    unsafe fn free_node(self) {
        unsafe {
            if !self.is_null() {
                let emotion = (*self).emotion;
                if !emotion.is_null() && emotion != NODATA.as_ptr() as *mut c_char {
                    libc::free(emotion as *mut _);
                }
                let excl = (*self).excl;
                if !excl.is_null() && excl != NODATA.as_ptr() as *mut c_char {
                    libc::free(excl as *mut _);
                }
                libc::free(self as *mut _);
            }
        }
    }
}

impl FreeNode for *mut ffi::JPCommonLabelBreathGroup {
    unsafe fn free_node(self) {
        if !self.is_null() {
            unsafe { libc::free(self as *mut _) };
        }
    }
}