Transparent type conversion in set_prop method

This commit is contained in:
Rafael Caricio 2020-01-05 20:41:16 +01:00
parent 7e247356c7
commit 8678823494

View file

@ -10,6 +10,7 @@ use dukbind::{
DUK_ERR_TYPE_ERROR, DUK_ERR_URI_ERROR, DUK_TYPE_BOOLEAN, DUK_TYPE_NONE, DUK_TYPE_NULL,
DUK_TYPE_NUMBER, DUK_TYPE_OBJECT, DUK_TYPE_STRING, DUK_TYPE_UNDEFINED,
};
use std::convert::TryInto;
use std::error::Error;
use std::f64;
use std::ffi::CStr;
@ -17,7 +18,6 @@ use std::fmt;
use std::mem;
use std::os::raw::c_void;
use std::ptr::NonNull;
use std::convert::TryInto;
/// An error code representing why an error occurred.
#[allow(missing_docs)]
@ -179,13 +179,23 @@ impl<'a> DukObject<'a> {
}
/// Set a property on this object.
pub fn set_prop(&self, name: &str, value: DukValue) -> DukResult<()> {
pub fn set_prop<'z, T>(&self, name: &str, value: T) -> DukResult<()>
where
T: TryInto<DukValue<'z>>,
{
let ctx = self.context.ctx.as_ptr();
unsafe {
duk_push_heapptr(ctx, self.heap.as_ptr());
if duk_is_undefined(ctx, -1) == 0 {
let mut ok = true;
match value {
let duk_val = match value.try_into() {
Ok(v) => v,
Err(_) => {
let err_msg = format!("Could not convert parameter to DukValue");
return Err(DukError::from_str(err_msg));
}
};
match duk_val {
DukValue::Undefined => duk_push_undefined(ctx),
DukValue::Null => duk_push_null(ctx),
DukValue::Number(ref n) => {
@ -267,6 +277,12 @@ impl<'a> From<String> for DukValue<'a> {
}
}
impl<'a> From<&'a str> for DukValue<'a> {
fn from(value: &str) -> Self {
DukValue::String(String::from(value))
}
}
impl<'a> TryInto<bool> for DukValue<'a> {
type Error = DukError;
@ -372,28 +388,26 @@ impl DukError {
/// Create a DukError from an error code (no message).
pub fn from_code(code: DukErrorCode) -> DukError {
DukError {
code: code,
code,
message: None,
}
}
/// Create a DukError from an error message (no code).
pub fn from_str(message: &str) -> DukError {
pub fn from_str<T: AsRef<str>>(message: T) -> DukError {
DukError {
code: DukErrorCode::Error,
message: Some(message.to_string()),
message: Some(String::from(message.as_ref())),
}
}
/// Create a DukError from a code and message.
pub fn from(code: DukErrorCode, message: &str) -> DukError {
DukError {
code: code,
code,
message: Some(message.to_string()),
}
}
/// Return the message stored in the DukError (or None if there isn't one).
pub fn to_string(&self) -> Option<String> {
self.message.clone()
}
}
impl Error for DukError {}
@ -543,7 +557,11 @@ mod tests {
#[test]
fn test_eval_to_string() {
let ctx = DukContext::new().unwrap();
let val: String = ctx.eval_string("'something'.toUpperCase()").unwrap().try_into().unwrap();
let val: String = ctx
.eval_string("'something'.toUpperCase()")
.unwrap()
.try_into()
.unwrap();
assert_eq!(val.as_str(), "SOMETHING");
}
@ -555,13 +573,33 @@ mod tests {
}
#[test]
fn test_set_obj_prop() {
fn test_set_obj_prop_str() {
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\"}");
obj.set_prop("other", String::from("name")).unwrap();
obj.set_prop("another", "name").unwrap();
assert_eq!(
obj.encode().unwrap().as_str(),
"{\"some\":\"thing\",\"other\":\"name\",\"another\":\"name\"}"
);
}
#[test]
fn test_set_obj_prop_bool() {
let ctx = DukContext::new().unwrap();
let val = ctx.eval_string("({\"some\":\"thing\"})").unwrap();
let obj = val.as_object().unwrap();
obj.set_prop("other", true).unwrap();
obj.set_prop("another", false).unwrap();
assert_eq!(
obj.encode().unwrap().as_str(),
"{\"some\":\"thing\",\"other\":true,\"another\":false}"
);
}
#[test]
@ -569,7 +607,9 @@ mod tests {
let ctx = DukContext::new().unwrap();
let val = ctx.eval_string("({\"some\":\"thing\"})").unwrap();
let obj = val.as_object().unwrap();
let value: String = obj.get_prop("some").unwrap().try_into().unwrap();
assert_eq!(value.as_str(), "thing");
}