use crate::context::VMError;
use crate::datatable::DataTable;
use crate::slot::ValueSlot;
use crate::value::Upvalue;
use crate::value_word::{ArrayView, ValueWord};
use std::sync::Arc;
#[inline]
pub fn require_string(nb: &ValueWord) -> Result<&str, VMError> {
nb.as_str()
.ok_or_else(|| VMError::type_mismatch("string", nb.type_name()))
}
#[inline]
pub fn require_arc_string(nb: &ValueWord) -> Result<&Arc<String>, VMError> {
nb.as_arc_string()
.ok_or_else(|| VMError::type_mismatch("string", nb.type_name()))
}
#[inline]
pub fn require_f64(nb: &ValueWord) -> Result<f64, VMError> {
nb.as_f64()
.ok_or_else(|| VMError::type_mismatch("number", nb.type_name()))
}
#[inline]
pub fn require_number(nb: &ValueWord) -> Result<f64, VMError> {
nb.as_number_coerce()
.ok_or_else(|| VMError::type_mismatch("number", nb.type_name()))
}
#[inline]
pub fn require_int(nb: &ValueWord) -> Result<i64, VMError> {
nb.as_i64()
.ok_or_else(|| VMError::type_mismatch("int", nb.type_name()))
}
#[inline]
pub fn require_bool(nb: &ValueWord) -> Result<bool, VMError> {
nb.as_bool()
.ok_or_else(|| VMError::type_mismatch("bool", nb.type_name()))
}
#[inline]
pub fn require_array(nb: &ValueWord) -> Result<ArrayView<'_>, VMError> {
nb.as_any_array()
.ok_or_else(|| VMError::type_mismatch("array", nb.type_name()))
}
#[inline]
pub fn require_datatable(nb: &ValueWord) -> Result<&Arc<DataTable>, VMError> {
nb.as_datatable()
.ok_or_else(|| VMError::type_mismatch("datatable", nb.type_name()))
}
#[inline]
pub fn require_typed_object(nb: &ValueWord) -> Result<(u64, &[ValueSlot], u64), VMError> {
nb.as_typed_object()
.ok_or_else(|| VMError::type_mismatch("object", nb.type_name()))
}
#[inline]
pub fn require_closure(nb: &ValueWord) -> Result<(u16, &[Upvalue]), VMError> {
nb.as_closure()
.ok_or_else(|| VMError::type_mismatch("closure", nb.type_name()))
}
#[inline]
pub fn nb_to_display_string(nb: &ValueWord) -> String {
format!("{}", nb)
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
#[test]
fn test_require_string_ok() {
let nb = ValueWord::from_string(Arc::new("hello".to_string()));
assert_eq!(require_string(&nb).unwrap(), "hello");
}
#[test]
fn test_require_string_err() {
let nb = ValueWord::from_f64(42.0);
let err = require_string(&nb).unwrap_err();
match err {
VMError::TypeError { expected, got } => {
assert_eq!(expected, "string");
assert_eq!(got, "number");
}
other => panic!("expected TypeError, got {:?}", other),
}
}
#[test]
fn test_require_number_coerce() {
let nb = ValueWord::from_f64(3.14);
assert_eq!(require_number(&nb).unwrap(), 3.14);
let nb = ValueWord::from_i64(42);
assert_eq!(require_number(&nb).unwrap(), 42.0);
let nb = ValueWord::from_string(Arc::new("x".to_string()));
assert!(require_number(&nb).is_err());
}
#[test]
fn test_require_int() {
let nb = ValueWord::from_i64(99);
assert_eq!(require_int(&nb).unwrap(), 99);
let nb = ValueWord::from_f64(1.5);
assert!(require_int(&nb).is_err());
}
#[test]
fn test_require_bool() {
let nb = ValueWord::from_bool(true);
assert_eq!(require_bool(&nb).unwrap(), true);
let nb = ValueWord::from_i64(1);
assert!(require_bool(&nb).is_err());
}
#[test]
fn test_require_array() {
let nb = ValueWord::from_array(Arc::new(vec![ValueWord::from_i64(1)]));
assert_eq!(require_array(&nb).unwrap().len(), 1);
let nb = ValueWord::from_f64(1.0);
assert!(require_array(&nb).is_err());
}
#[test]
fn test_require_typed_object() {
let nb = ValueWord::from_f64(1.0);
let err = require_typed_object(&nb).unwrap_err();
match err {
VMError::TypeError { expected, got } => {
assert_eq!(expected, "object");
assert_eq!(got, "number");
}
other => panic!("expected TypeError, got {:?}", other),
}
}
#[test]
fn test_nb_to_display_string() {
assert_eq!(nb_to_display_string(&ValueWord::from_f64(3.14)), "3.14");
assert_eq!(nb_to_display_string(&ValueWord::from_i64(42)), "42");
assert_eq!(nb_to_display_string(&ValueWord::from_bool(true)), "true");
assert_eq!(nb_to_display_string(&ValueWord::none()), "none");
let s = ValueWord::from_string(Arc::new("hello".to_string()));
assert_eq!(nb_to_display_string(&s), "hello");
}
}