Use std type conversion traits

This commit is contained in:
Rafael Caricio 2020-01-05 19:04:34 +01:00
parent 79d72c1158
commit 7e247356c7

View file

@ -8,14 +8,16 @@ use dukbind::{
duk_push_pointer, duk_push_undefined, duk_put_prop, duk_put_prop_lstring, duk_size_t, duk_push_pointer, duk_push_undefined, duk_put_prop, duk_put_prop_lstring, duk_size_t,
DUK_ERR_ERROR, DUK_ERR_EVAL_ERROR, DUK_ERR_NONE, DUK_ERR_RANGE_ERROR, DUK_ERR_SYNTAX_ERROR, DUK_ERR_ERROR, DUK_ERR_EVAL_ERROR, DUK_ERR_NONE, DUK_ERR_RANGE_ERROR, DUK_ERR_SYNTAX_ERROR,
DUK_ERR_TYPE_ERROR, DUK_ERR_URI_ERROR, DUK_TYPE_BOOLEAN, DUK_TYPE_NONE, DUK_TYPE_NULL, DUK_ERR_TYPE_ERROR, DUK_ERR_URI_ERROR, DUK_TYPE_BOOLEAN, DUK_TYPE_NONE, DUK_TYPE_NULL,
DUK_TYPE_NUMBER, DUK_TYPE_STRING, DUK_TYPE_UNDEFINED, DUK_TYPE_NUMBER, DUK_TYPE_OBJECT, DUK_TYPE_STRING, DUK_TYPE_UNDEFINED,
}; };
use std::error::Error; use std::error::Error;
use std::f64; use std::f64;
use std::ffi::CStr; use std::ffi::CStr;
use std::fmt; use std::fmt;
use std::mem;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::ptr::NonNull; use std::ptr::NonNull;
use std::convert::TryInto;
/// An error code representing why an error occurred. /// An error code representing why an error occurred.
#[allow(missing_docs)] #[allow(missing_docs)]
@ -200,9 +202,7 @@ impl<'a> DukObject<'a> {
duk_push_number(ctx, n.as_f64()); duk_push_number(ctx, n.as_f64());
} }
} }
DukValue::Boolean(b) => { DukValue::Boolean(b) => duk_push_boolean(ctx, b as duk_bool_t),
duk_push_boolean(ctx, value.as_duk_bool().expect("Not a boolean!"))
}
DukValue::String(s) => { DukValue::String(s) => {
let t = &s; let t = &s;
duk_push_lstring(ctx, t.as_ptr() as *const i8, t.len() as duk_size_t); duk_push_lstring(ctx, t.as_ptr() as *const i8, t.len() as duk_size_t);
@ -255,41 +255,49 @@ pub enum DukValue<'a> {
Object(DukObject<'a>), Object(DukObject<'a>),
} }
impl<'a> DukValue<'a> { impl<'a> From<bool> for DukValue<'a> {
/// Return the value as a string. fn from(value: bool) -> Self {
pub fn as_str(&self) -> Option<String> { DukValue::Boolean(value)
match self {
DukValue::Undefined => Some(String::from("undefined")),
DukValue::Null => Some(String::from("null")),
DukValue::Number(n) => Some(String::from(n.as_str())),
DukValue::Boolean(b) => Some(b.to_string()),
DukValue::String(s) => Some(s.clone()),
DukValue::Object(o) => o.encode(),
}
} }
}
/// Return the value as a duk_bool_t (u32). impl<'a> From<String> for DukValue<'a> {
pub fn as_duk_bool(&self) -> Option<duk_bool_t> { fn from(value: String) -> Self {
match self { DukValue::String(value)
DukValue::Boolean(b) => { }
if *b { }
Some(1)
impl<'a> TryInto<bool> for DukValue<'a> {
type Error = DukError;
fn try_into(self) -> Result<bool, Self::Error> {
if let DukValue::Boolean(b) = self {
Ok(b)
} else { } else {
Some(0) Err(DukError::from_str("Could not convert value to boolean"))
}
}
_ => None,
} }
} }
}
/// Return the value as a bool. impl<'a> TryInto<String> for DukValue<'a> {
pub fn as_bool(&self) -> Option<bool> { type Error = DukError;
fn try_into(self) -> Result<String, Self::Error> {
match self { match self {
DukValue::Boolean(b) => Some(*b), DukValue::Undefined => Ok(String::from("undefined")),
_ => None, DukValue::Null => Ok(String::from("null")),
DukValue::Number(n) => Ok(String::from(n.as_str())),
DukValue::Boolean(b) => Ok(b.to_string()),
DukValue::String(s) => Ok(s.clone()),
DukValue::Object(o) => match o.encode() {
Some(encoded) => Ok(encoded),
None => Err(DukError::from_str("Could not convert object to String")),
},
} }
} }
}
impl<'a> DukValue<'a> {
/// Return the value as a DukNumber. /// Return the value as a DukNumber.
pub fn as_number(&self) -> Option<DukNumber> { pub fn as_number(&self) -> Option<DukNumber> {
match self { match self {
@ -498,14 +506,9 @@ impl DukContext {
); );
let val = self.get_value(); let val = self.get_value();
duk_pop(self.ctx.as_ptr()); duk_pop(self.ctx.as_ptr());
match val.as_str() { let val: String = val.try_into()?;
Some(v) => {
use std::mem;
let c: DukErrorCode = mem::transmute(code); let c: DukErrorCode = mem::transmute(code);
Err(DukError::from(c, v.as_ref())) Err(DukError::from(c, val.as_ref()))
}
None => Err(DukError::from_code(DukErrorCode::Error)),
}
} }
} }
} }
@ -519,6 +522,7 @@ mod tests {
fn test_create_context() { fn test_create_context() {
let ctx = DukContext::new(); let ctx = DukContext::new();
assert!(ctx.is_ok()); assert!(ctx.is_ok());
drop(ctx);
} }
#[test] #[test]
@ -529,19 +533,35 @@ mod tests {
assert_eq!(val, DukNumber::Int(15)); assert_eq!(val, DukNumber::Int(15));
} }
#[test]
fn test_eval_to_bool() {
let ctx = DukContext::new().unwrap();
let val: bool = ctx.eval_string("true").unwrap().try_into().unwrap();
assert_eq!(val, true);
}
#[test] #[test]
fn test_eval_to_string() { fn test_eval_to_string() {
let ctx = DukContext::new().unwrap(); let ctx = DukContext::new().unwrap();
let val = ctx.eval_string("'something'.toUpperCase()").unwrap(); let val: String = ctx.eval_string("'something'.toUpperCase()").unwrap().try_into().unwrap();
let val = val.as_str().unwrap(); assert_eq!(val.as_str(), "SOMETHING");
assert_eq!(val, String::from("SOMETHING"));
} }
#[test] #[test]
fn test_eval_to_object() { fn test_eval_to_object() {
let ctx = DukContext::new().unwrap(); let ctx = DukContext::new().unwrap();
let val = ctx.eval_string("({\"some\":\"thing\"})").unwrap(); let val = ctx.eval_string("({\"some\":\"thing\"})").unwrap();
let _ = val.as_object().unwrap(); assert!(val.as_object().is_some());
}
#[test]
fn test_set_obj_prop() {
let ctx = DukContext::new().unwrap();
let val = ctx.eval_string("({\"some\":\"thing\"})").unwrap();
let obj = val.as_object().unwrap();
let s = String::from("name");
obj.set_prop("other", s.into()).unwrap();
assert_eq!(obj.encode().unwrap().as_str(), "{\"some\":\"thing\",\"other\":\"name\"}");
} }
#[test] #[test]
@ -549,18 +569,16 @@ mod tests {
let ctx = DukContext::new().unwrap(); let ctx = DukContext::new().unwrap();
let val = ctx.eval_string("({\"some\":\"thing\"})").unwrap(); let val = ctx.eval_string("({\"some\":\"thing\"})").unwrap();
let obj = val.as_object().unwrap(); let obj = val.as_object().unwrap();
assert_eq!( let value: String = obj.get_prop("some").unwrap().try_into().unwrap();
obj.get_prop("some").unwrap().as_str().unwrap(), assert_eq!(value.as_str(), "thing");
String::from("thing")
);
} }
#[test] #[test]
fn test_eval_ret() { fn test_eval_ret() {
// Create a new context // Create a new context
let mut ctx = DukContext::new().unwrap(); let ctx = DukContext::new().unwrap();
// Obtain array value from eval // Obtain array value from eval
let mut val = ctx.eval_string("([1,2,3])").unwrap(); let val = ctx.eval_string("([1,2,3])").unwrap();
// Get the array as an object // Get the array as an object
let obj = val.as_object().expect("WAS NOT AN OBJECT"); let obj = val.as_object().expect("WAS NOT AN OBJECT");
// Set index 3 as 4 // Set index 3 as 4