#[cfg(test)]
mod tests;
use core::ffi::c_char;
use crate::{
Ctx, drop,
error::{CueError, Error},
};
type CueValueHandle = usize;
unsafe extern "C" {
fn cue_validate(
v: CueValueHandle,
opts: *mut core::ffi::c_void,
) -> usize;
fn cue_is_equal(
a: CueValueHandle,
b: CueValueHandle,
) -> bool;
fn cue_unify(
a: CueValueHandle,
b: CueValueHandle,
) -> CueValueHandle;
fn cue_compile_string(
ctx: usize,
src: *mut c_char,
opts: *mut core::ffi::c_void,
out: *mut CueValueHandle,
) -> usize;
fn cue_compile_bytes(
ctx: usize,
data: *mut core::ffi::c_void,
len: usize,
opts: *mut core::ffi::c_void,
out: *mut CueValueHandle,
) -> usize;
fn cue_dec_json(
v: CueValueHandle,
res: *mut *mut core::ffi::c_void,
size: *mut usize,
) -> usize;
}
#[derive(Debug)]
pub struct Value(CueValueHandle);
impl Drop for Value {
fn drop(&mut self) {
unsafe { drop::cue_free(self.0) }
}
}
impl PartialEq for Value {
fn eq(
&self,
other: &Self,
) -> bool {
unsafe { cue_is_equal(self.0, other.0) }
}
}
impl Value {
pub fn compile_string(
ctx: &Ctx,
src: &str,
) -> Result<Self, Error> {
let cstr = std::ffi::CString::new(src).map_err(Error::StringContainsNul)?;
let mut handle: CueValueHandle = 0;
let err = unsafe {
cue_compile_string(
ctx.handle(),
cstr.as_ptr().cast_mut(),
core::ptr::null_mut(),
&raw mut handle,
)
};
if err != 0 {
return Err(Error::Cue(CueError(err)));
}
Ok(Self(handle))
}
pub fn compile_bytes(
ctx: &Ctx,
src: &[u8],
) -> Result<Self, Error> {
let mut handle: CueValueHandle = 0;
let err = unsafe {
cue_compile_bytes(
ctx.handle(),
src.as_ptr().cast::<core::ffi::c_void>().cast_mut(),
src.len(),
core::ptr::null_mut(),
&raw mut handle,
)
};
if err != 0 {
return Err(Error::Cue(CueError(err)));
}
Ok(Self(handle))
}
pub fn to_json_bytes(&self) -> Result<bytes::Bytes, Error> {
let mut ptr: *mut core::ffi::c_void = core::ptr::null_mut();
let mut size: usize = 0;
let err = unsafe { cue_dec_json(self.0, &raw mut ptr, &raw mut size) };
if err != 0 {
return Err(Error::Cue(CueError(err)));
}
let result = bytes::Bytes::copy_from_slice(unsafe {
core::slice::from_raw_parts(ptr.cast::<u8>(), size)
});
unsafe { drop::libc_free(ptr) };
Ok(result)
}
#[must_use]
pub fn unify(
v1: &Value,
v2: &Value,
) -> Self {
let handle = unsafe { cue_unify(v1.0, v2.0) };
Self(handle)
}
pub fn is_valid(&self) -> Result<(), Error> {
let err = unsafe { cue_validate(self.0, core::ptr::null_mut()) };
if err != 0 {
return Err(Error::Cue(CueError(err)));
}
Ok(())
}
}