#![allow(dead_code)]
use std::ffi::c_char;
use std::sync::Arc;
use blazen_uniffi::errors::BlazenError as InnerError;
use blazen_uniffi::llm::{
CompletionModel as InnerCompletionModel, CompletionResponse as InnerCompletionResponse,
EmbeddingModel as InnerEmbeddingModel, EmbeddingResponse as InnerEmbeddingResponse,
};
use crate::error::BlazenError;
use crate::future::BlazenFuture;
use crate::llm_records::{
BlazenCompletionRequest, BlazenCompletionResponse, BlazenEmbeddingResponse,
};
use crate::runtime::runtime;
use crate::string::{alloc_cstring, cstr_to_str};
fn write_error(out_err: *mut *mut BlazenError, err: InnerError) {
if !out_err.is_null() {
unsafe {
*out_err = BlazenError::from(err).into_ptr();
}
}
}
fn write_internal_error(out_err: *mut *mut BlazenError, message: &str) {
write_error(
out_err,
InnerError::Internal {
message: message.to_owned(),
},
);
}
unsafe fn ptr_array_to_strings(ptrs: *const *const c_char, count: usize) -> Option<Vec<String>> {
if count == 0 {
return Some(Vec::new());
}
if ptrs.is_null() {
return None;
}
let mut out = Vec::with_capacity(count);
for i in 0..count {
let p = unsafe { *ptrs.add(i) };
let s = unsafe { cstr_to_str(p) }?;
out.push(s.to_owned());
}
Some(out)
}
pub struct BlazenCompletionModel(pub(crate) Arc<InnerCompletionModel>);
impl BlazenCompletionModel {
pub(crate) fn into_ptr(self) -> *mut BlazenCompletionModel {
Box::into_raw(Box::new(self))
}
}
impl From<Arc<InnerCompletionModel>> for BlazenCompletionModel {
fn from(inner: Arc<InnerCompletionModel>) -> Self {
Self(inner)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_completion_model_model_id(
model: *const BlazenCompletionModel,
) -> *mut c_char {
if model.is_null() {
return std::ptr::null_mut();
}
let m = unsafe { &*model };
let id = Arc::clone(&m.0).model_id();
alloc_cstring(&id)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_completion_model_complete_blocking(
model: *const BlazenCompletionModel,
request: *mut BlazenCompletionRequest,
out_response: *mut *mut BlazenCompletionResponse,
out_err: *mut *mut BlazenError,
) -> i32 {
if model.is_null() {
write_internal_error(
out_err,
"blazen_completion_model_complete_blocking: null model",
);
return -1;
}
if request.is_null() {
write_internal_error(
out_err,
"blazen_completion_model_complete_blocking: null request",
);
return -1;
}
let m = unsafe { &*model };
let inner_model = Arc::clone(&m.0);
let request_box = unsafe { Box::from_raw(request) };
let inner_request = request_box.0;
let result: Result<InnerCompletionResponse, InnerError> =
runtime().block_on(async move { inner_model.complete(inner_request).await });
match result {
Ok(resp) => {
if !out_response.is_null() {
unsafe {
*out_response = BlazenCompletionResponse::from(resp).into_ptr();
}
}
0
}
Err(e) => {
write_error(out_err, e);
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_completion_model_complete(
model: *const BlazenCompletionModel,
request: *mut BlazenCompletionRequest,
) -> *mut BlazenFuture {
if model.is_null() {
if !request.is_null() {
drop(unsafe { Box::from_raw(request) });
}
return std::ptr::null_mut();
}
if request.is_null() {
return std::ptr::null_mut();
}
let m = unsafe { &*model };
let inner_model = Arc::clone(&m.0);
let request_box = unsafe { Box::from_raw(request) };
let inner_request = request_box.0;
BlazenFuture::spawn(async move { inner_model.complete(inner_request).await })
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_completion_model_free(model: *mut BlazenCompletionModel) {
if model.is_null() {
return;
}
drop(unsafe { Box::from_raw(model) });
}
pub struct BlazenEmbeddingModel(pub(crate) Arc<InnerEmbeddingModel>);
impl BlazenEmbeddingModel {
pub(crate) fn into_ptr(self) -> *mut BlazenEmbeddingModel {
Box::into_raw(Box::new(self))
}
}
impl From<Arc<InnerEmbeddingModel>> for BlazenEmbeddingModel {
fn from(inner: Arc<InnerEmbeddingModel>) -> Self {
Self(inner)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_embedding_model_model_id(
model: *const BlazenEmbeddingModel,
) -> *mut c_char {
if model.is_null() {
return std::ptr::null_mut();
}
let m = unsafe { &*model };
let id = Arc::clone(&m.0).model_id();
alloc_cstring(&id)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_embedding_model_dimensions(
model: *const BlazenEmbeddingModel,
) -> u32 {
if model.is_null() {
return 0;
}
let m = unsafe { &*model };
Arc::clone(&m.0).dimensions()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_embedding_model_embed_blocking(
model: *const BlazenEmbeddingModel,
inputs: *const *const c_char,
inputs_count: usize,
out_response: *mut *mut BlazenEmbeddingResponse,
out_err: *mut *mut BlazenError,
) -> i32 {
if model.is_null() {
write_internal_error(out_err, "blazen_embedding_model_embed_blocking: null model");
return -1;
}
let Some(owned_inputs) = (unsafe { ptr_array_to_strings(inputs, inputs_count) }) else {
write_internal_error(
out_err,
"blazen_embedding_model_embed_blocking: null or non-UTF-8 input string",
);
return -1;
};
let m = unsafe { &*model };
let inner_model = Arc::clone(&m.0);
let result: Result<InnerEmbeddingResponse, InnerError> =
runtime().block_on(async move { inner_model.embed(owned_inputs).await });
match result {
Ok(resp) => {
if !out_response.is_null() {
unsafe {
*out_response = BlazenEmbeddingResponse::from(resp).into_ptr();
}
}
0
}
Err(e) => {
write_error(out_err, e);
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_embedding_model_embed(
model: *const BlazenEmbeddingModel,
inputs: *const *const c_char,
inputs_count: usize,
) -> *mut BlazenFuture {
if model.is_null() {
return std::ptr::null_mut();
}
let Some(owned_inputs) = (unsafe { ptr_array_to_strings(inputs, inputs_count) }) else {
return std::ptr::null_mut();
};
let m = unsafe { &*model };
let inner_model = Arc::clone(&m.0);
BlazenFuture::spawn(async move { inner_model.embed(owned_inputs).await })
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_embedding_model_free(model: *mut BlazenEmbeddingModel) {
if model.is_null() {
return;
}
drop(unsafe { Box::from_raw(model) });
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_future_take_completion_response(
fut: *mut BlazenFuture,
out: *mut *mut BlazenCompletionResponse,
err: *mut *mut BlazenError,
) -> i32 {
match unsafe { BlazenFuture::take_typed::<InnerCompletionResponse>(fut) } {
Ok(v) => {
if !out.is_null() {
unsafe {
*out = BlazenCompletionResponse::from(v).into_ptr();
}
}
0
}
Err(e) => {
write_error(err, e);
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn blazen_future_take_embedding_response(
fut: *mut BlazenFuture,
out: *mut *mut BlazenEmbeddingResponse,
err: *mut *mut BlazenError,
) -> i32 {
match unsafe { BlazenFuture::take_typed::<InnerEmbeddingResponse>(fut) } {
Ok(v) => {
if !out.is_null() {
unsafe {
*out = BlazenEmbeddingResponse::from(v).into_ptr();
}
}
0
}
Err(e) => {
write_error(err, e);
-1
}
}
}