use crate::error::{check, RayError, Result};
use crate::raw::{self, Raw};
use crate::runtime::assert_on_runtime_thread;
use crate::value::Value;
use rayforce_sys as sys;
#[inline]
unsafe fn own(ptr: Raw) -> Value {
match check(ptr) {
Ok(p) => Value::from_owned(p),
Err(e) => panic!("rayforce: failed to construct atom: {e}"),
}
}
impl Value {
pub fn bool(v: bool) -> Value {
assert_on_runtime_thread("Value::bool");
unsafe { own(sys::ray_bool(v)) }
}
pub fn u8(v: u8) -> Value {
assert_on_runtime_thread("Value::u8");
unsafe { own(sys::ray_u8(v)) }
}
pub fn i16(v: i16) -> Value {
assert_on_runtime_thread("Value::i16");
unsafe { own(sys::ray_i16(v)) }
}
pub fn i32(v: i32) -> Value {
assert_on_runtime_thread("Value::i32");
unsafe { own(sys::ray_i32(v)) }
}
pub fn i64(v: i64) -> Value {
assert_on_runtime_thread("Value::i64");
unsafe { own(sys::ray_i64(v)) }
}
pub fn f32(v: f32) -> Value {
assert_on_runtime_thread("Value::f32");
unsafe { own(sys::ray_f32(v)) }
}
pub fn f64(v: f64) -> Value {
assert_on_runtime_thread("Value::f64");
unsafe { own(sys::ray_f64(v)) }
}
pub fn sym(s: &str) -> Value {
assert_on_runtime_thread("Value::sym");
unsafe {
let id = sys::ray_sym_intern(s.as_ptr() as *const _, s.len());
own(sys::ray_sym(id))
}
}
pub fn string(s: &str) -> Value {
assert_on_runtime_thread("Value::string");
unsafe { own(sys::ray_str(s.as_ptr() as *const _, s.len())) }
}
pub fn name_ref(name: &str) -> Value {
assert_on_runtime_thread("Value::name_ref");
unsafe {
let id = sys::ray_sym_intern(name.as_ptr() as *const _, name.len());
let v = own(sys::ray_sym(id));
raw::set_attrs(v.as_ptr(), 0);
v
}
}
pub fn date_days(days: i32) -> Value {
assert_on_runtime_thread("Value::date_days");
unsafe { own(sys::ray_date(days as i64)) }
}
pub fn time_millis(ms: i32) -> Value {
assert_on_runtime_thread("Value::time_millis");
unsafe { own(sys::ray_time(ms as i64)) }
}
pub fn timestamp_nanos(ns: i64) -> Value {
assert_on_runtime_thread("Value::timestamp_nanos");
unsafe { own(sys::ray_timestamp(ns)) }
}
pub fn guid(bytes: &[u8; 16]) -> Value {
assert_on_runtime_thread("Value::guid");
unsafe { own(sys::ray_guid(bytes.as_ptr())) }
}
pub fn typed_null(abs_type: i8) -> Value {
assert_on_runtime_thread("Value::typed_null");
unsafe { own(sys::ray_typed_null(abs_type)) }
}
pub fn is_atom_null(&self) -> bool {
unsafe { raw::atom_is_null(self.as_ptr()) }
}
pub fn as_bool(&self) -> Result<bool> {
self.expect_atom(sys::RAY_BOOL)?;
Ok(unsafe { raw::as_b8(self.as_ptr()) })
}
pub fn as_u8(&self) -> Result<u8> {
self.expect_atom(sys::RAY_U8)?;
Ok(unsafe { raw::as_u8(self.as_ptr()) })
}
pub fn as_i16(&self) -> Result<i16> {
self.expect_atom(sys::RAY_I16)?;
Ok(unsafe { raw::as_i16(self.as_ptr()) })
}
pub fn as_i32(&self) -> Result<i32> {
self.expect_atom(sys::RAY_I32)?;
Ok(unsafe { raw::as_i32(self.as_ptr()) })
}
pub fn as_i64(&self) -> Result<i64> {
self.expect_atom(sys::RAY_I64)?;
Ok(unsafe { raw::as_i64(self.as_ptr()) })
}
pub fn as_f32(&self) -> Result<f32> {
self.expect_atom(sys::RAY_F32)?;
Ok(unsafe { raw::as_f64(self.as_ptr()) as f32 })
}
pub fn as_f64(&self) -> Result<f64> {
self.expect_atom(sys::RAY_F64)?;
Ok(unsafe { raw::as_f64(self.as_ptr()) })
}
pub fn as_sym(&self) -> Result<String> {
self.expect_atom(sys::RAY_SYM)?;
unsafe {
let id = raw::as_i64(self.as_ptr());
let s = sys::ray_sym_str(id); if s.is_null() {
return Ok(String::new());
}
Ok(read_str_atom(s))
}
}
pub fn as_string(&self) -> Result<String> {
self.expect_atom(sys::RAY_STR)?;
Ok(unsafe { read_str_atom(self.as_ptr()) })
}
pub fn as_date_days(&self) -> Result<i32> {
self.expect_atom(sys::RAY_DATE)?;
Ok(unsafe { raw::as_i32(self.as_ptr()) })
}
pub fn as_time_millis(&self) -> Result<i32> {
self.expect_atom(sys::RAY_TIME)?;
Ok(unsafe { raw::as_i32(self.as_ptr()) })
}
pub fn as_timestamp_nanos(&self) -> Result<i64> {
self.expect_atom(sys::RAY_TIMESTAMP)?;
Ok(unsafe { raw::as_i64(self.as_ptr()) })
}
pub fn as_guid(&self) -> Result<[u8; 16]> {
self.expect_atom(sys::RAY_GUID)?;
unsafe { Ok(raw::guid_bytes(self.as_ptr()).unwrap_or([0u8; 16])) }
}
fn expect_atom(&self, abs: u32) -> Result<()> {
if self.type_code() as i32 == -(abs as i32) {
Ok(())
} else {
Err(RayError::binding(format!(
"expected atom of type {}, got type tag {}",
abs,
self.type_code()
)))
}
}
}
unsafe fn read_str_atom(p: Raw) -> String {
let ptr = sys::ray_str_ptr(p).cast::<u8>();
let n = sys::ray_str_len(p);
if ptr.is_null() || n == 0 {
String::new()
} else {
String::from_utf8_lossy(std::slice::from_raw_parts(ptr, n)).into_owned()
}
}