Skip to content

Commit

Permalink
[project-vvm-async-api] output_系引数がunalignedであることを許す (VOICEVOX#534)
Browse files Browse the repository at this point in the history
  • Loading branch information
qryxip authored Jul 1, 2023
1 parent a00ff98 commit b8b8484
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 40 deletions.
73 changes: 41 additions & 32 deletions crates/voicevox_core_c_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use std::env;
use std::ffi::{CStr, CString};
use std::fmt;
use std::io::{self, IsTerminal, Write};
use std::mem::MaybeUninit;
use std::os::raw::c_char;
use std::ptr::NonNull;
use std::sync::{Arc, Mutex, MutexGuard};
use tokio::runtime::Runtime;
use tracing_subscriber::fmt::format::Writer;
Expand Down Expand Up @@ -88,12 +88,12 @@ pub struct OpenJtalkRc {
#[no_mangle]
pub unsafe extern "C" fn voicevox_open_jtalk_rc_new(
open_jtalk_dic_dir: *const c_char,
out_open_jtalk: &mut MaybeUninit<Box<OpenJtalkRc>>,
out_open_jtalk: NonNull<Box<OpenJtalkRc>>,
) -> VoicevoxResultCode {
into_result_code_with_error((|| {
let open_jtalk_dic_dir = ensure_utf8(CStr::from_ptr(open_jtalk_dic_dir))?;
let open_jtalk = OpenJtalkRc::new_with_initialize(open_jtalk_dic_dir)?;
out_open_jtalk.write(Box::new(open_jtalk));
let open_jtalk = OpenJtalkRc::new_with_initialize(open_jtalk_dic_dir)?.into();
out_open_jtalk.as_ptr().write_unaligned(open_jtalk);
Ok(())
})())
}
Expand Down Expand Up @@ -176,13 +176,14 @@ pub type VoicevoxStyleId = u32;
#[no_mangle]
pub unsafe extern "C" fn voicevox_voice_model_new_from_path(
path: *const c_char,
out_model: &mut MaybeUninit<Box<VoicevoxVoiceModel>>,
out_model: NonNull<Box<VoicevoxVoiceModel>>,
) -> VoicevoxResultCode {
into_result_code_with_error((|| {
let model = RUNTIME.block_on(VoicevoxVoiceModel::from_path(ensure_utf8(
CStr::from_ptr(path),
)?))?;
out_model.write(Box::new(model));
let path = ensure_utf8(CStr::from_ptr(path))?;
let model = RUNTIME
.block_on(VoicevoxVoiceModel::from_path(path))?
.into();
out_model.as_ptr().write_unaligned(model);
Ok(())
})())
}
Expand Down Expand Up @@ -234,18 +235,20 @@ pub struct VoicevoxSynthesizer {
/// # Safety
/// @param out_synthesizer 自動でheapメモリが割り当てられるので ::voicevox_synthesizer_delete で解放する必要がある
#[no_mangle]
pub extern "C" fn voicevox_synthesizer_new_with_initialize(
pub unsafe extern "C" fn voicevox_synthesizer_new_with_initialize(
open_jtalk: &OpenJtalkRc,
options: VoicevoxInitializeOptions,
out_synthesizer: &mut MaybeUninit<Box<VoicevoxSynthesizer>>,
out_synthesizer: NonNull<Box<VoicevoxSynthesizer>>,
) -> VoicevoxResultCode {
into_result_code_with_error((|| {
let options = options.into();

let synthesizer = RUNTIME.block_on(VoicevoxSynthesizer::new_with_initialize(
open_jtalk, &options,
))?;
out_synthesizer.write(Box::new(synthesizer));
let synthesizer = RUNTIME
.block_on(VoicevoxSynthesizer::new_with_initialize(
open_jtalk, &options,
))?
.into();
out_synthesizer.as_ptr().write_unaligned(synthesizer);
Ok(())
})())
}
Expand Down Expand Up @@ -351,13 +354,13 @@ pub extern "C" fn voicevox_synthesizer_get_metas_json(
/// # Safety
/// @param output_supported_devices_json 自動でheapメモリが割り当てられるので ::voicevox_json_free で解放する必要がある
#[no_mangle]
pub extern "C" fn voicevox_create_supported_devices_json(
output_supported_devices_json: &mut MaybeUninit<*mut c_char>,
pub unsafe extern "C" fn voicevox_create_supported_devices_json(
output_supported_devices_json: NonNull<*mut c_char>,
) -> VoicevoxResultCode {
into_result_code_with_error((|| {
let supported_devices =
CString::new(SupportedDevices::create()?.to_json().to_string()).unwrap();
output_supported_devices_json.write(
output_supported_devices_json.as_ptr().write_unaligned(
C_STRING_DROP_CHECKER
.whitelist(supported_devices)
.into_raw(),
Expand Down Expand Up @@ -394,7 +397,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_audio_query(
text: *const c_char,
style_id: VoicevoxStyleId,
options: VoicevoxAudioQueryOptions,
output_audio_query_json: &mut MaybeUninit<*mut c_char>,
output_audio_query_json: NonNull<*mut c_char>,
) -> VoicevoxResultCode {
into_result_code_with_error((|| {
let text = CStr::from_ptr(text);
Expand All @@ -406,7 +409,9 @@ pub unsafe extern "C" fn voicevox_synthesizer_audio_query(
))?;
let audio_query = CString::new(audio_query_model_to_json(&audio_query))
.expect("should not contain '\\0'");
output_audio_query_json.write(C_STRING_DROP_CHECKER.whitelist(audio_query).into_raw());
output_audio_query_json
.as_ptr()
.write_unaligned(C_STRING_DROP_CHECKER.whitelist(audio_query).into_raw());
Ok(())
})())
}
Expand Down Expand Up @@ -438,7 +443,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_accent_phrases(
text: *const c_char,
style_id: VoicevoxStyleId,
options: VoicevoxAccentPhrasesOptions,
output_accent_phrases_json: &mut MaybeUninit<*mut c_char>,
output_accent_phrases_json: NonNull<*mut c_char>,
) -> VoicevoxResultCode {
into_result_code_with_error((|| {
let text = ensure_utf8(CStr::from_ptr(text))?;
Expand All @@ -450,7 +455,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_create_accent_phrases(
let accent_phrases = CString::new(accent_phrases_to_json(&accent_phrases))
.expect("should not contain '\\0'");
output_accent_phrases_json
.write(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw());
.as_ptr()
.write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw());
Ok(())
})())
}
Expand All @@ -469,7 +475,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_data(
synthesizer: &VoicevoxSynthesizer,
accent_phrases_json: *const c_char,
style_id: VoicevoxStyleId,
output_accent_phrases_json: &mut MaybeUninit<*mut c_char>,
output_accent_phrases_json: NonNull<*mut c_char>,
) -> VoicevoxResultCode {
into_result_code_with_error((|| {
let accent_phrases: Vec<AccentPhraseModel> =
Expand All @@ -483,7 +489,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_data(
let accent_phrases = CString::new(accent_phrases_to_json(&accent_phrases))
.expect("should not contain '\\0'");
output_accent_phrases_json
.write(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw());
.as_ptr()
.write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw());
Ok(())
})())
}
Expand All @@ -502,7 +509,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_phoneme_length(
synthesizer: &VoicevoxSynthesizer,
accent_phrases_json: *const c_char,
style_id: VoicevoxStyleId,
output_accent_phrases_json: &mut MaybeUninit<*mut c_char>,
output_accent_phrases_json: NonNull<*mut c_char>,
) -> VoicevoxResultCode {
into_result_code_with_error((|| {
let accent_phrases: Vec<AccentPhraseModel> =
Expand All @@ -516,7 +523,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_phoneme_length(
let accent_phrases = CString::new(accent_phrases_to_json(&accent_phrases))
.expect("should not contain '\\0'");
output_accent_phrases_json
.write(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw());
.as_ptr()
.write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw());
Ok(())
})())
}
Expand All @@ -535,7 +543,7 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_pitch(
synthesizer: &VoicevoxSynthesizer,
accent_phrases_json: *const c_char,
style_id: VoicevoxStyleId,
output_accent_phrases_json: &mut MaybeUninit<*mut c_char>,
output_accent_phrases_json: NonNull<*mut c_char>,
) -> VoicevoxResultCode {
into_result_code_with_error((|| {
let accent_phrases: Vec<AccentPhraseModel> =
Expand All @@ -549,7 +557,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_replace_mora_pitch(
let accent_phrases = CString::new(accent_phrases_to_json(&accent_phrases))
.expect("should not contain '\\0'");
output_accent_phrases_json
.write(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw());
.as_ptr()
.write_unaligned(C_STRING_DROP_CHECKER.whitelist(accent_phrases).into_raw());
Ok(())
})())
}
Expand Down Expand Up @@ -583,8 +592,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_synthesis(
audio_query_json: *const c_char,
style_id: VoicevoxStyleId,
options: VoicevoxSynthesisOptions,
output_wav_length: &mut MaybeUninit<usize>,
output_wav: &mut MaybeUninit<*mut u8>,
output_wav_length: NonNull<usize>,
output_wav: NonNull<*mut u8>,
) -> VoicevoxResultCode {
into_result_code_with_error((|| {
let audio_query_json = CStr::from_ptr(audio_query_json)
Expand Down Expand Up @@ -633,8 +642,8 @@ pub unsafe extern "C" fn voicevox_synthesizer_tts(
text: *const c_char,
style_id: VoicevoxStyleId,
options: VoicevoxTtsOptions,
output_wav_length: &mut MaybeUninit<usize>,
output_wav: &mut MaybeUninit<*mut u8>,
output_wav_length: NonNull<usize>,
output_wav: NonNull<*mut u8>,
) -> VoicevoxResultCode {
into_result_code_with_error((|| {
let text = ensure_utf8(CStr::from_ptr(text))?;
Expand Down
25 changes: 17 additions & 8 deletions crates/voicevox_core_c_api/src/slice_owner.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{cell::UnsafeCell, collections::BTreeMap, mem::MaybeUninit, sync::Mutex};
use std::{cell::UnsafeCell, collections::BTreeMap, ptr::NonNull, sync::Mutex};

/// Cの世界に貸し出す`[u8]`の所有者(owner)。
///
Expand Down Expand Up @@ -27,11 +27,16 @@ impl<T> SliceOwner<T> {
}

/// `Box<[T]>`を所有し、その先頭ポインタと長さを参照としてC API利用者に与える。
pub(crate) fn own_and_lend(
///
/// # Safety
///
/// - `out_ptr`は書き込みについて有効でなければならない(ただし`*mut T`は有効である必要は無い)。
/// - `out_len`は書き込みについて有効でなければならない。
pub(crate) unsafe fn own_and_lend(
&self,
slice: impl Into<Box<[T]>>,
out_ptr: &mut MaybeUninit<*mut T>,
out_len: &mut MaybeUninit<usize>,
out_ptr: NonNull<*mut T>,
out_len: NonNull<usize>,
) {
let mut slices = self.slices.lock().unwrap();

Expand All @@ -42,8 +47,8 @@ impl<T> SliceOwner<T> {
let duplicated = slices.insert(ptr as usize, slice.into()).is_some();
assert!(!duplicated, "duplicated");

out_ptr.write(ptr);
out_len.write(len);
out_ptr.as_ptr().write_volatile(ptr);
out_len.as_ptr().write_volatile(len);
}

/// `own_and_lend`でC API利用者に貸し出したポインタに対応する`Box<[u8]>`をデストラクトする。
Expand All @@ -63,7 +68,7 @@ impl<T> SliceOwner<T> {

#[cfg(test)]
mod tests {
use std::mem::MaybeUninit;
use std::{mem::MaybeUninit, ptr::NonNull};

use super::SliceOwner;

Expand All @@ -87,7 +92,11 @@ mod tests {
let (ptr, len) = unsafe {
let mut ptr = MaybeUninit::uninit();
let mut len = MaybeUninit::uninit();
owner.own_and_lend(vec, &mut ptr, &mut len);
owner.own_and_lend(
vec,
NonNull::new(ptr.as_mut_ptr()).unwrap(),
NonNull::new(len.as_mut_ptr()).unwrap(),
);
(ptr.assume_init(), len.assume_init())
};
assert_eq!(expected_len, len);
Expand Down

0 comments on commit b8b8484

Please sign in to comment.