/*! Rust interface to the [`sciter::value`](https://github.com/c-smile/sciter-sdk/blob/master/include/value.h). Sciter [`Value`](struct.Value.html) holds superset of JSON objects. It can contain as pure JSON objects (numbers, strings, maps and arrays) as internal objects like DOM elements, proxies of script functions, objects and arrays. ## Basic usage You can create an empty (undefined) Sciter value with [`Value::new()`](struct.Value.html): ``` use sciter::Value; let v = Value::new(); assert!(v.is_undefined()); assert!(!v.is_null()); ``` Or explicitly create `Value` of the specified type: ``` use sciter::Value; let v = Value::null(); assert!(v.is_null()); let v = Value::symbol("hello"); assert!(v.is_symbol()); assert!(v.is_string()); let v = Value::error("hello"); assert!(v.is_error_string()); assert!(v.is_string()); // allocate a new array with 4 empty elements let v = Value::array(4); assert!(v.is_array()); assert!(v.len() == 4); // allocate a new value with map type let v = Value::map(); assert!(v.is_map()); assert!(v.len() == 0); ``` Also there is conversion from Rust types: ``` use sciter::Value; let v = Value::from(true); assert!(v.is_bool()); let v = Value::from(1); assert!(v.is_int()); let v = Value::from(1.0); assert!(v.is_float()); let v = Value::from("hello"); assert!(v.is_string()); let v = Value::from(b"123".as_ref()); assert!(v.is_bytes()); ``` And from a sequence of objects: ``` use sciter::Value; let v: Value = ["1","2","3"].iter().cloned().collect(); assert!(v.is_array()); assert_eq!(v.len(), 3); assert_eq!(v[0], Value::from("1")); ``` And also there is a couple of macros for container literals with specific type which are just shorthands for manual construction using the [`set_item()`](struct.Value.html#method.set_item) and [`push()`](struct.Value.html#method.push) methods: ``` # #[macro_use] extern crate sciter; # fn main() { let map = vmap! { "one" => 1, "two" => 2.0, "three" => "", }; assert!(map.is_map()); assert_eq!(map.len(), 3); let array = varray![1, 2.0, "three"]; assert!(array.is_array()); assert_eq!(array.len(), 3); # } ``` To access its contents you should use one of [`to_`](struct.Value.html#method.to_int) methods: ``` use sciter::Value; let v = Value::from(4); assert_eq!(v.to_int(), Some(4)); ``` Note that there are two functions that convert `Value` to JSON and back: ``` use sciter::Value; let mut v: Value = "[1, 2, 3, 4]".parse().unwrap(); let json_str = v.into_string(); ``` Array access: ``` use sciter::Value; let mut v: Value = "[10, 20]".parse().unwrap(); assert_eq!(v[0], Value::from(10)); // explicit arguments: v.set(1, Value::from(21)); v.set(2, Value::from(22)); // implicit arguments: v.set(1, 21); v.set(2, 22); assert_eq!(v.len(), 3); assert!(v.get(0).is_int()); ``` Map access: ``` use sciter::Value; let mut v: Value = "{one: 1, two: 2}".parse().unwrap(); assert_eq!(v["one"], 1.into()); assert_eq!(v.get_item("one"), 1.into()); assert_eq!(v[Value::from("one")], Value::from(1)); v.set_item("three", 3); assert!(v.get_item("one").is_int()); ``` . */ use ::{_API}; use capi::sctypes::*; use capi::scvalue::{VALUE_UNIT_TYPE_STRING, VALUE_UNIT_TYPE_OBJECT, VALUE_UNIT_UNDEFINED}; pub use capi::scvalue::{VALUE_RESULT, VALUE_STRING_CVT_TYPE, VALUE_TYPE}; use capi::scvalue::VALUE; use ::om::IAsset; // TODO: `get`, `get_item` methods should return `Option` /// `sciter::value` wrapper. /// /// See the [module-level](index.html) documentation. pub struct Value { data: VALUE, tmp: * mut Value, } /// `sciter::Value` can be transferred across thread boundaries. unsafe impl Send for Value {} impl Value { /// Return a new Sciter value object ([`undefined`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined)). pub fn new() -> Value { Value { data: VALUE::default(), tmp: ::std::ptr::null_mut() } } /// Make an explicit [array](https://sciter.com/docs/content/script/Array.htm) value with the given length. pub fn array(length: usize) -> Value { let mut me = Value::new(); (_API.ValueIntDataSet)(me.as_ptr(), length as i32, VALUE_TYPE::T_ARRAY as UINT, 0); return me; } /// Make an explicit [map](https://sciter.com/docs/content/script/Object.htm) value. pub fn map() -> Value { let mut me = Value::new(); (_API.ValueIntDataSet)(me.as_ptr(), 0i32, VALUE_TYPE::T_MAP as UINT, 0); return me; } /// Make an explicit json [null](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null) value. pub fn null() -> Value { let mut me = Value::new(); me.data.t = VALUE_TYPE::T_NULL; return me; } /// Make an explicit `nothing` (where did it come from?). pub fn nothing() -> Value { let mut me = Value::new(); me.data.t = VALUE_TYPE::T_UNDEFINED; me.data.u = VALUE_UNIT_UNDEFINED::UT_NOTHING as UINT; return me; } /// Make Sciter [symbol](https://sciter.com/docs/content/script/language/Syntax.htm#symbol-literals) value. pub fn symbol(val: &str) -> Value { let mut me = Value::new(); me.assign_str(val, VALUE_UNIT_TYPE_STRING::SYMBOL); return me; } /// Make Sciter [error](https://sciter.com/docs/content/script/Error.htm) value. pub fn error(val: &str) -> Value { let mut me = Value::new(); me.assign_str(val, VALUE_UNIT_TYPE_STRING::ERROR); return me; } /// Make Sciter [color](https://sciter.com/docs/content/script/Color.htm) value, in `0xAABBGGRR` form. pub fn color(val: u32) -> Value { let mut me = Value::new(); (_API.ValueIntDataSet)(me.as_ptr(), val as i32, VALUE_TYPE::T_COLOR as u32, 0); return me; } /// Make Sciter [duration](https://sciter.com/docs/content/script/language/Types.htm) value, in seconds. pub fn duration(val: f64) -> Value { let mut me = Value::new(); (_API.ValueFloatDataSet)(me.as_ptr(), val, VALUE_TYPE::T_DURATION as u32, 0); return me; } /// Make Sciter [angle](https://sciter.com/docs/content/script/Angle.htm) value, in radians. pub fn angle(val: f64) -> Value { let mut me = Value::new(); (_API.ValueFloatDataSet)(me.as_ptr(), val, VALUE_TYPE::T_ANGLE as u32, 0); return me; } /// Parse a json string into value. Returns the number of chars left unparsed in case of error. pub fn parse(val: &str) -> Result { return Value::parse_as(val, VALUE_STRING_CVT_TYPE::JSON_LITERAL); } /// Parse a json string into value. Returns the number of chars left unparsed in case of error. pub fn parse_as(val: &str, how: VALUE_STRING_CVT_TYPE) -> Result { let mut me = Value::new(); let (s,n) = s2wn!(val); let ok: u32 = (_API.ValueFromString)(me.as_ptr(), s.as_ptr(), n, how); if ok == 0 { Ok(me) } else { Err(ok as usize) } } /// Value to asset. pub fn to_asset(&self) -> Option<&mut IAsset> { if self.is_asset() { let mut val = 0_i64; if (_API.ValueInt64Data)(self.as_cptr(), &mut val) == VALUE_RESULT::OK { let ptr = val as usize as *mut IAsset; let asset = unsafe { &mut *ptr }; return Some(asset); } } return None; } #[doc(hidden)] pub fn as_ptr(&mut self) -> *mut VALUE { &mut self.data as *mut VALUE } #[doc(hidden)] pub fn as_cptr(&self) -> *const VALUE { &self.data as *const VALUE } /// Get the inner type of the value. pub fn get_type(&self) -> VALUE_TYPE { return self.data.t; } /// Get the inner type and its subtype (e.g. units) of the value. pub fn full_type(&self) -> (VALUE_TYPE, UINT) { return (self.data.t, self.data.u); } /// Convert `T_OBJECT` value type to JSON `T_MAP` or `T_ARRAY` types. /// /// Also must be used if you need to pass values between different threads. pub fn isolate(&mut self) { (_API.ValueIsolate)(self.as_ptr()); } /// Clear the value. It deallocates all assosiated structures that are not used anywhere else. pub fn clear(&mut self) -> &mut Value { (_API.ValueClear)(self.as_ptr()); self } /// Return the number of items in the `T_ARRAY`, `T_MAP`, `T_FUNCTION` and `T_OBJECT` value types. pub fn len(&self) -> usize { let mut n: INT = 0; (_API.ValueElementsCount)(self.as_cptr(), &mut n); return n as usize; } /// Append another value to the end of `T_ARRAY` value. pub fn push>(&mut self, src: T) { (_API.ValueNthElementValueSet)(self.as_ptr(), self.len() as INT, src.into().as_cptr()); } /// Insert or set value at the given `index` of `T_ARRAY`, `T_MAP`, `T_FUNCTION` and `T_OBJECT` value. pub fn set>(&mut self, index: usize, src: T) { (_API.ValueNthElementValueSet)(self.as_ptr(), index as INT, src.into().as_cptr()); } /// Retreive value of sub-element at `index`. /// /// * `T_ARRAY` - nth element of the array; /// * `T_MAP` - value of the nth key/value pair in the map; /// * `T_FUNCTION` - value of the nth argument of the function. /// pub fn get(&self, index: usize) -> Value { let mut v = Value::new(); (_API.ValueNthElementValue)(self.as_cptr(), index as INT, v.as_ptr()); return v; } /// Insert or set value of the sub-element by `key`. /// /// * `T_MAP` - sets named value in the map; /// * `T_OBJECT` - sets value of property of the object; /// * `T_FUNCTION` - sets named argument of the function; /// * otherwise it converts self to the map type and adds the key/value to it. /// pub fn set_item, TValue: Into>(&mut self, key: TKey, value: TValue) { (_API.ValueSetValueToKey)(self.as_ptr(), key.into().as_cptr(), value.into().as_cptr()); } /// Retrieve the value of a sub-element by key. pub fn get_item>(&self, key: T) -> Value { let mut v = Value::new(); (_API.ValueGetValueOfKey)(self.as_cptr(), key.into().as_cptr(), v.as_ptr()); return v; } /// Retrieve the key of a sub-element by `index`. pub fn key_at(&self, index: usize) -> Value { let mut v = Value::new(); (_API.ValueNthElementKey)(self.as_cptr(), index as INT, v.as_ptr()); return v; } /// An iterator visiting all keys of key/value pairs in the map. /// /// * `T_MAP` - keys of key/value pairs in the map; /// * `T_OBJECT` - names of key/value properties in the object; /// * `T_FUNCTION` - names of arguments of the function (if any). /// /// The iterator element type is `Value` (as a key). pub fn keys(&self) -> KeyIterator { KeyIterator { base: self, index: 0, count: self.len(), } } /// An iterator visiting all values in arbitrary order. /// /// * `T_ARRAY` - elements of the array; /// * `T_MAP` - values of key/value pairs in the map; /// * `T_OBJECT` - values of key/value properties in the object; /// * `T_FUNCTION` - values of arguments of the function. /// /// The iterator element type is `Value`. pub fn values(&self) -> SeqIterator { SeqIterator { base: self, index: 0, count: self.len(), } } /// An iterator visiting all key-value pairs in arbitrary order. /// /// The `Value` must has a key-value type (map, object, function). /// /// The iterator element type is `(Value, Value)`. pub fn items(&self) -> Vec<(Value, Value)> { type VecType = Vec<(Value, Value)>; let mut result = Vec::with_capacity(self.len()); extern "system" fn on_pair(param: LPVOID, pkey: *const VALUE, pval: *const VALUE) -> BOOL { assert!(!param.is_null()); unsafe { let result = param as *mut VecType; let result = &mut *result; let item = (Value::copy_from(pkey), Value::copy_from(pval)); result.push(item); } return true as BOOL; } let ptr = &mut result as *mut VecType; (_API.ValueEnumElements)(self.as_cptr(), on_pair, ptr as LPVOID); return result; } /// Value to integer. pub fn to_int(&self) -> Option { let mut val = 0i32; match (_API.ValueIntData)(self.as_cptr(), &mut val) { VALUE_RESULT::OK => Some(val), _ => None } } /// Value to bool. pub fn to_bool(&self) -> Option { let mut val = 0i32; match (_API.ValueIntData)(self.as_cptr(), &mut val) { VALUE_RESULT::OK => Some(val != 0), _ => None } } /// Value to float. pub fn to_float(&self) -> Option { let mut val = 0f64; match (_API.ValueFloatData)(self.as_cptr(), &mut val) { VALUE_RESULT::OK => Some(val), _ => None } } /// Value to color. pub fn to_color(&self) -> Option { let mut val = 0i32; match (_API.ValueIntData)(self.as_cptr(), &mut val) { VALUE_RESULT::OK => Some(val as u32), _ => None } } /// Value to duration. pub fn to_duration(&self) -> Option { let mut val = 0f64; match (_API.ValueFloatData)(self.as_cptr(), &mut val) { VALUE_RESULT::OK => Some(val), _ => None } } /// Value to angle. pub fn to_angle(&self) -> Option { let mut val = 0f64; match (_API.ValueFloatData)(self.as_cptr(), &mut val) { VALUE_RESULT::OK => Some(val), _ => None } } /// Value as string for `T_STRING` type. pub fn as_string(&self) -> Option { let mut s = 0 as LPCWSTR; let mut n = 0 as UINT; match (_API.ValueStringData)(self.as_cptr(), &mut s, &mut n) { VALUE_RESULT::OK => Some(::utf::w2sn(s, n as usize)), _ => None } } /// Value to json string (converted in-place). _Subject to change._ pub fn into_string(mut self) -> String { (_API.ValueToString)(self.as_ptr(), VALUE_STRING_CVT_TYPE::JSON_LITERAL); return self.as_string().unwrap(); } /// Value as a byte slice for `T_BYTES` type. pub fn as_bytes(&self) -> Option<&[u8]> { let mut s = 0 as LPCBYTE; let mut n = 0 as UINT; match (_API.ValueBinaryData)(self.as_cptr(), &mut s, &mut n) { VALUE_RESULT::OK => Some(unsafe { ::std::slice::from_raw_parts(s, n as usize) }), _ => None } } /// Value to byte vector for `T_BYTES` type. pub fn to_bytes(&self) -> Option> { match self.as_bytes() { Some(r) => Some(r.to_owned()), None => None, } } /// Function invocation for `T_OBJECT` with `UT_OBJECT_FUNCTION` value type. /// /// Calls the tiscript function or method holded at `Value` with context of `this` object /// that will be known as _this_ inside that function (it is optional for global functions). /// /// The `name` here is an url or a name of the script - used for error reporting in script. /// /// You can use the [`make_args!(args...)`](../macro.make_args.html) macro which helps you /// to construct script arguments from Rust types. pub fn call(&self, this: Option, args: &[Value], name: Option<&str>) -> Result { let mut rv = Value::new(); let argv = Value::pack_args(args); let name = s2w!(name.unwrap_or("")); let ok = (_API.ValueInvoke)(self.as_cptr(), this.unwrap_or_default().as_ptr(), argv.len() as UINT, argv.as_ptr(), rv.as_ptr(), name.as_ptr()); match ok { VALUE_RESULT::OK => Ok(rv), _ => Err(ok) } } #[doc(hidden)] pub fn pack_to(&self, dst: &mut VALUE) { (_API.ValueCopy)(dst, self.as_cptr()); } #[doc(hidden)] pub fn pack_args(args: &[Value]) -> Vec { let argc = args.len(); let mut argv: Vec = Vec::with_capacity(argc); argv.resize(argc, VALUE::default()); for i in 0..argc { args[i].pack_to(&mut argv[i]); } return argv; } #[doc(hidden)] pub unsafe fn unpack_from(args: * const VALUE, count: UINT) -> Vec { let argc = count as usize; let mut argv: Vec = Vec::with_capacity(argc); assert!(argc == 0 || !args.is_null()); let args = ::std::slice::from_raw_parts(args, argc); for arg in args { argv.push(Value::copy_from(arg)); } return argv; } #[doc(hidden)] unsafe fn copy_from(ptr: *const VALUE) -> Value { assert!(!ptr.is_null()); let mut v = Value::new(); (_API.ValueCopy)(v.as_ptr(), ptr); return v; } #[allow(clippy::mut_from_ref)] fn ensure_tmp_mut(&self) -> &mut Value { let cp = self as *const Value; let mp = cp as *mut Value; let me = unsafe { &mut *mp }; return me.ensure_tmp(); } fn ensure_tmp(&mut self) -> &mut Value { if self.tmp.is_null() { let tmp = Box::new(Value::new()); self.tmp = Box::into_raw(tmp); } return unsafe { &mut *self.tmp }; } /// Returns `true` is `self` is `undefined` or has zero elements. pub fn is_empty(&self) -> bool { self.is_undefined() || self.len() == 0 } #[allow(missing_docs)] pub fn is_undefined(&self) -> bool { self.data.t == VALUE_TYPE::T_UNDEFINED && self.data.u == 0 } #[allow(missing_docs)] pub fn is_null(&self) -> bool { self.data.t == VALUE_TYPE::T_NULL } #[allow(missing_docs)] pub fn is_nothing(&self) -> bool { self.data.t == VALUE_TYPE::T_UNDEFINED && self.data.u == VALUE_UNIT_UNDEFINED::UT_NOTHING as UINT } #[allow(missing_docs)] pub fn is_bool(&self) -> bool { self.data.t == VALUE_TYPE::T_BOOL } #[allow(missing_docs)] pub fn is_int(&self) -> bool { self.data.t == VALUE_TYPE::T_INT } #[allow(missing_docs)] pub fn is_float(&self) -> bool { self.data.t == VALUE_TYPE::T_FLOAT } #[allow(missing_docs)] pub fn is_bytes(&self) -> bool { self.data.t == VALUE_TYPE::T_BYTES } #[allow(missing_docs)] pub fn is_string(&self) -> bool { self.data.t == VALUE_TYPE::T_STRING } #[allow(missing_docs)] pub fn is_symbol(&self) -> bool { self.data.t == VALUE_TYPE::T_STRING && self.data.u == VALUE_UNIT_TYPE_STRING::SYMBOL as UINT } #[allow(missing_docs)] pub fn is_error_string(&self) -> bool { self.data.t == VALUE_TYPE::T_STRING && self.data.u == VALUE_UNIT_TYPE_STRING::ERROR as UINT } #[allow(missing_docs)] pub fn is_date(&self) -> bool { self.data.t == VALUE_TYPE::T_DATE } #[allow(missing_docs)] pub fn is_currency(&self) -> bool { self.data.t == VALUE_TYPE::T_CURRENCY } #[allow(missing_docs)] pub fn is_color(&self) -> bool { self.data.t == VALUE_TYPE::T_COLOR } #[allow(missing_docs)] pub fn is_duration(&self) -> bool { self.data.t == VALUE_TYPE::T_DURATION } #[allow(missing_docs)] pub fn is_angle(&self) -> bool { self.data.t == VALUE_TYPE::T_ANGLE } #[allow(missing_docs)] pub fn is_map(&self) -> bool { self.data.t == VALUE_TYPE::T_MAP } #[allow(missing_docs)] pub fn is_array(&self) -> bool { self.data.t == VALUE_TYPE::T_ARRAY } #[allow(missing_docs)] pub fn is_function(&self) -> bool { self.data.t == VALUE_TYPE::T_FUNCTION } #[allow(missing_docs)] pub fn is_native_function(&self) -> bool { (_API.ValueIsNativeFunctor)(self.as_cptr()) != 0 } #[allow(missing_docs)] pub fn is_object(&self) -> bool { self.data.t == VALUE_TYPE::T_OBJECT } #[allow(missing_docs)] pub fn is_asset(&self) -> bool { self.data.t == VALUE_TYPE::T_ASSET } // script types: #[allow(missing_docs)] pub fn is_object_array(&self) -> bool { self.data.t == VALUE_TYPE::T_OBJECT && self.data.u == VALUE_UNIT_TYPE_OBJECT::ARRAY as UINT } #[allow(missing_docs)] pub fn is_object_map(&self) -> bool { self.data.t == VALUE_TYPE::T_OBJECT && self.data.u == VALUE_UNIT_TYPE_OBJECT::OBJECT as UINT } #[allow(missing_docs)] pub fn is_object_class(&self) -> bool { self.data.t == VALUE_TYPE::T_OBJECT && self.data.u == VALUE_UNIT_TYPE_OBJECT::OBJECT as UINT } #[allow(missing_docs)] pub fn is_object_native(&self) -> bool { self.data.t == VALUE_TYPE::T_OBJECT && self.data.u == VALUE_UNIT_TYPE_OBJECT::NATIVE as UINT } #[allow(missing_docs)] pub fn is_object_function(&self) -> bool { self.data.t == VALUE_TYPE::T_OBJECT && self.data.u == VALUE_UNIT_TYPE_OBJECT::FUNCTION as UINT } #[allow(missing_docs)] pub fn is_object_error(&self) -> bool { self.data.t == VALUE_TYPE::T_OBJECT && self.data.u == VALUE_UNIT_TYPE_OBJECT::ERROR as UINT } #[allow(missing_docs)] pub fn is_dom_element(&self) -> bool { self.data.t == VALUE_TYPE::T_DOM_OBJECT } // generic check (native or object): #[allow(missing_docs)] pub fn is_varray(&self) -> bool { self.is_array() || self.is_object() } #[allow(missing_docs)] pub fn is_vmap(&self) -> bool { self.is_map() || self.is_object_map() } #[allow(missing_docs)] pub fn is_vfunction(&self) -> bool { self.is_function() || self.is_object_function() || self.is_native_function() } #[allow(missing_docs)] pub fn is_verror(&self) -> bool { self.is_error_string() || self.is_object_error() } fn assign_str(&mut self, val: &str, unit: VALUE_UNIT_TYPE_STRING) -> VALUE_RESULT { let (s,n) = s2wn!(val); return (_API.ValueStringDataSet)(self.as_ptr(), s.as_ptr(), n, unit as UINT); } } /// Print `Value` as json string impl ::std::fmt::Display for Value { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { let copy = self.clone(); let re = copy.into_string(); f.write_str(&re) } } /// Print `Value` as json string with explicit type showed. impl ::std::fmt::Debug for Value { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { let mut tname = format!("{:?}", self.data.t); if self.is_undefined() || self.is_null() { return f.write_str(&tname[2..].to_lowercase()); } else if self.is_nothing() { return f.write_str("nothing"); } else if self.is_string() && self.data.u != 0 { // VALUE_UNIT_TYPE_STRING let units = [ ("file", 0xfffe), ("symbol", 0xffff), ("string", 0), ("error", 1), ("secure", 2), ("url", 3), ("selector", 4), ]; tname.push_str(":"); if let Some(name) = units.iter().find(|&&x| x.1 == self.data.u) { tname.push_str(name.0); } else { tname.push_str(&self.data.u.to_string()); } } else if self.is_object() { // VALUE_UNIT_TYPE_OBJECT let units = ["array", "object", "class", "native", "function", "error"]; let u = self.data.u as usize; tname.push_str(":"); if u < units.len() { tname.push_str(units[u]); } else { tname.push_str(&u.to_string()); } } else if self.data.u != 0 { // VALUE_UNIT_TYPE // redundant? like "length:7:12px" instead of "length:12px" (7 == `UT_PX`). // tname.push_str(":"); // tname.push_str(&self.data.u.to_string()); } f.write_str(&tname[2..].to_lowercase())?; f.write_str(":")?; write!(f, "{}", &self) } } /// Destroy pointed value. impl Drop for Value { fn drop(&mut self) { if !self.tmp.is_null() { unsafe { Box::from_raw(self.tmp) }; } (_API.ValueClear)(self.as_ptr()); } } /// Return default value (`undefined`). impl Default for Value { fn default() -> Self { return Value::new(); } } /// Copies value. /// /// All allocated objects are reference counted so copying is just a matter of increasing reference counts. impl Clone for Value { fn clone(&self) -> Self { let mut dst = Value::new(); (_API.ValueCopy)(dst.as_ptr(), self.as_cptr()); return dst; } } /// Compare two values. impl ::std::cmp::PartialEq for Value { fn eq(&self, other: &Self) -> bool { match (_API.ValueCompare)(self.as_cptr(), other.as_cptr()) { VALUE_RESULT::OK_TRUE => true, // VALUE_RESULT::OK => false, _ => false } } } /// Get item by index for array type. impl ::std::ops::Index for Value { type Output = Value; fn index(&self, index: usize) -> &Self::Output { let tmp = self.ensure_tmp_mut(); (_API.ValueNthElementValue)(self.as_cptr(), index as INT, tmp.as_ptr()); return tmp; } } /// Set item by index for array type. #[cfg(notworking)] impl ::std::ops::IndexMut for Value { fn index_mut(&mut self, index: usize) -> &mut Value { let tmp = self.ensure_tmp_mut(); (_API.ValueNthElementValue)(self.as_cptr(), index as INT, tmp.as_ptr()); return tmp; } } /// Get item by key for map type. impl ::std::ops::Index for Value { type Output = Value; fn index(&self, key: Value) -> &Self::Output { let tmp = self.ensure_tmp_mut(); (_API.ValueGetValueOfKey)(self.as_cptr(), key.as_cptr(), tmp.as_ptr()); return tmp; } } /// Get item by string key for map type. impl ::std::ops::Index<&'static str> for Value { type Output = Value; fn index(&self, key: &'static str) -> &Self::Output { let tmp = self.ensure_tmp_mut(); (_API.ValueGetValueOfKey)(self.as_cptr(), Value::from(key).as_cptr(), tmp.as_ptr()); return tmp; } } /// Set item by key for map type. #[cfg(notworking)] impl ::std::ops::IndexMut for Value { fn index_mut<'a>(&'a mut self, key: Value) -> &'a mut Value { let ptr = self.as_ptr(); let tmp = self.ensure_tmp(); (_API.ValueSetValueToKey)(ptr, key.as_cptr(), tmp.as_ptr()); return tmp; } } /// Value from nothing (`()`) for empty return values. /// /// Returns `undefined` value. impl From<()> for Value { fn from(_: ()) -> Self { Value::new() } } /// Value from a native `VALUE` object. impl<'a> From<&'a VALUE> for Value { fn from(val: &'a VALUE) -> Self { unsafe { Value::copy_from(val as *const _) } } } /// Value from integer. impl From for Value { // Note that there is no generic 64-bit integers at Sciter, only Date/Currency types. // There is a double (f64) for large numbers as a workaround. fn from(val: i32) -> Self { let mut me = Value::new(); (_API.ValueIntDataSet)(me.as_ptr(), val, VALUE_TYPE::T_INT as UINT, 0); return me; } } /// Value from integer. impl From<&i32> for Value { // Note that there is no generic 64-bit integers at Sciter, only Date/Currency types. // There is a double (f64) for large numbers as a workaround. fn from(val: &i32) -> Self { let mut me = Value::new(); (_API.ValueIntDataSet)(me.as_ptr(), *val, VALUE_TYPE::T_INT as UINT, 0); return me; } } /// Value from float. impl From for Value { fn from(val: f64) -> Self { let mut me = Value::new(); (_API.ValueFloatDataSet)(me.as_ptr(), val, VALUE_TYPE::T_FLOAT as UINT, 0); return me; } } /// Value from float. impl From<&f64> for Value { fn from(val: &f64) -> Self { let mut me = Value::new(); (_API.ValueFloatDataSet)(me.as_ptr(), *val, VALUE_TYPE::T_FLOAT as UINT, 0); return me; } } /// Value from bool. impl From for Value { fn from(val: bool) -> Self { let mut me = Value::new(); (_API.ValueIntDataSet)(me.as_ptr(), val as INT, VALUE_TYPE::T_BOOL as UINT, 0); return me; } } /// Value from bool. impl From<&bool> for Value { fn from(val: &bool) -> Self { let mut me = Value::new(); (_API.ValueIntDataSet)(me.as_ptr(), *val as INT, VALUE_TYPE::T_BOOL as UINT, 0); return me; } } /// Value from string. impl<'a> From<&'a str> for Value { fn from(val: &'a str) -> Self { let mut me = Value::new(); me.assign_str(val, VALUE_UNIT_TYPE_STRING::STRING); return me; } } /// Value from string. impl From for Value { fn from(val: String) -> Self { let mut me = Value::new(); me.assign_str(&val, VALUE_UNIT_TYPE_STRING::STRING); return me; } } impl<'a> From<&'a String> for Value { fn from(val: &'a String) -> Self { let mut me = Value::new(); me.assign_str(val, VALUE_UNIT_TYPE_STRING::STRING); return me; } } /// Value from json string. impl ::std::str::FromStr for Value { type Err = VALUE_RESULT; fn from_str(val: &str) -> Result { Value::parse(val).or(Err(VALUE_RESULT::BAD_PARAMETER)) } } /// Value from binary array (sequence of bytes). impl<'a> From<&'a [u8]> for Value { fn from(val: &'a [u8]) -> Self { let mut me = Value::new(); (_API.ValueBinaryDataSet)(me.as_ptr(), val.as_ptr(), val.len() as UINT, VALUE_TYPE::T_BYTES as UINT, 0); return me; } } impl From> for Value where T: Into, E: std::fmt::Display { fn from(val: Result) -> Self { match val { Ok(v) => v.into(), Err(e) => Value::error(&e.to_string()), } } } // /// Value from sequence of items satisfying `Into`. // impl ::std::iter::FromIterator> for Value { // fn from_iter>>(iterator: I) -> Self { // let iterator = iterator.into_iter(); // let capacity = iterator.size_hint().0; // let mut v = Value::array(capacity); // for i in iterator { // v.push(Value::from(i)); // } // return v; // } // } /// Value from sequence of `Value`. impl ::std::iter::FromIterator for Value { fn from_iter>(iterator: I) -> Self { let iterator = iterator.into_iter(); let capacity = iterator.size_hint().0; let mut v = Value::array(capacity); for (i, m) in iterator.enumerate() { v.set(i, m); } return v; } } /// Value from sequence of `i32`. impl ::std::iter::FromIterator for Value { fn from_iter>(iterator: I) -> Self { let iterator = iterator.into_iter(); let capacity = iterator.size_hint().0; let mut v = Value::array(capacity); for (i, m) in iterator.enumerate() { v.set(i, Value::from(m)); } return v; } } /// Value from sequence of `f64`. impl ::std::iter::FromIterator for Value { fn from_iter>(iterator: I) -> Self { let iterator = iterator.into_iter(); let capacity = iterator.size_hint().0; let mut v = Value::array(capacity); for (i, m) in iterator.enumerate() { v.set(i, Value::from(m)); } return v; } } /// Value from sequence of `&str`. impl<'a> ::std::iter::FromIterator<&'a str> for Value { fn from_iter>(iterator: I) -> Self { let iterator = iterator.into_iter(); let capacity = iterator.size_hint().0; let mut v = Value::array(capacity); for (i, m) in iterator.enumerate() { v.set(i, Value::from(m)); } return v; } } /// Value from sequence of `String`. impl ::std::iter::FromIterator for Value { fn from_iter>(iterator: I) -> Self { let iterator = iterator.into_iter(); let capacity = iterator.size_hint().0; let mut v = Value::array(capacity); for (i, m) in iterator.enumerate() { v.set(i, Value::from(m)); } return v; } } // /// Value from function. // impl From for Value // where F: Fn(&[Value]) -> Value // { // fn from(f: F) -> Value { // let mut v = Value::new(); // let boxed = Box::new(f); // let ptr = Box::into_raw(boxed); // dropped in `_functor_release` // (_API.ValueNativeFunctorSet)(v.as_ptr(), _functor_invoke::, _functor_release::, ptr as LPVOID); // return v; // } // } /// Value from function. impl From for Value where F: Fn(&[Value]) -> R, R: Into, { fn from(f: F) -> Value { let mut v = Value::new(); let boxed = Box::new(f); let ptr = Box::into_raw(boxed); // dropped in `_functor_release` (_API.ValueNativeFunctorSet)(v.as_ptr(), _functor_invoke::, _functor_release::, ptr as LPVOID); return v; } } /// Value from asset. impl From>> for Value { fn from(ptr: Box>) -> Value { let ptr = Box::into_raw(ptr); let mut me = Value::new(); (_API.ValueInt64DataSet)(me.as_ptr(), ptr as usize as i64, VALUE_TYPE::T_ASSET as u32, 0); return me; } } extern "C" fn _functor_release(tag: LPVOID) { // reconstruct handler from pointer let ptr = tag as *mut F; let boxed = unsafe { Box::from_raw(ptr) }; // and forget it drop(boxed); } extern "C" fn _functor_invoke(tag: LPVOID, argc: UINT, argv: *const VALUE, retval: *mut VALUE) where F: Fn(&[Value]) -> R, R: Into, { // reconstruct handler from pointer let ptr = tag as *mut F; let me = unsafe { &mut *ptr }; let retval = unsafe { &mut *retval }; let args = unsafe { Value::unpack_from(argv, argc) }; let rv = me(&args); let rv: Value = rv.into(); rv.pack_to(retval) } /// Helper trait pub trait FromValue { /// Converts value to specified type. fn from_value(v: &Value) -> Option where Self: Sized; } impl FromValue for Value { fn from_value(v: &Value) -> Option { Some(v.clone()) } } impl FromValue for bool { fn from_value(v: &Value) -> Option { v.to_bool() } } impl FromValue for i32 { fn from_value(v: &Value) -> Option { v.to_int() } } impl FromValue for f64 { fn from_value(v: &Value) -> Option { v.to_float() } } impl FromValue for Vec { fn from_value(v: &Value) -> Option { v.to_bytes() } } impl FromValue for String { fn from_value(v: &Value) -> Option { v.as_string() } } /// An iterator visiting all keys of key/value pairs in the map-like `Value` objects. #[doc(hidden)] pub struct KeyIterator<'a> { base: &'a Value, index: usize, count: usize, } impl<'a> ::std::iter::Iterator for KeyIterator<'a> { type Item = Value; fn next(&mut self) -> Option { if self.index < self.count { self.index += 1; Some(self.base.key_at(self.index - 1)) } else { None } } fn size_hint(&self) -> (usize, Option) { let remain = self.count - self.index; (remain, Some(remain)) } fn count(self) -> usize { self.count } } /// An iterator able to yield keys from both `Value`'s ends. impl<'a> ::std::iter::DoubleEndedIterator for KeyIterator<'a> { fn next_back(&mut self) -> Option { if self.index == self.count || self.count == 0 { None } else { self.count -= 1; Some(self.base.key_at(self.count)) } } } /// An iterator over the sub-elements of a `Value`. #[doc(hidden)] pub struct SeqIterator<'a> { base: &'a Value, index: usize, count: usize, } impl<'a> ::std::iter::Iterator for SeqIterator<'a> { type Item = Value; fn next(&mut self) -> Option { if self.index < self.count { self.index += 1; Some(self.base.get(self.index - 1)) } else { None } } fn size_hint(&self) -> (usize, Option) { let remain = self.count - self.index; (remain, Some(remain)) } fn count(self) -> usize { self.count } } /// An iterator able to yield sub-elements from both `Value`'s ends. impl<'a> ::std::iter::DoubleEndedIterator for SeqIterator<'a> { fn next_back(&mut self) -> Option { if self.index == self.count || self.count == 0 { None } else { self.count -= 1; Some(self.base.get(self.count)) } } } /// Conversion into an `Iterator`. /// /// Adds the `for` loop syntax support: `for subitem in &value {]`. impl<'a> ::std::iter::IntoIterator for &'a Value { type Item = Value; type IntoIter = SeqIterator<'a>; fn into_iter(self) -> Self::IntoIter { self.values() } } #[cfg(test)] mod tests { #![allow(unused_imports)] use super::{Value, FromValue}; use capi::scvalue::{VALUE, VALUE_TYPE}; use std::mem; use ::{_API}; fn check1(a: i32) { assert_eq!(a, 12); } #[test] fn test_from_value() { let v = Value::from(12); check1( match FromValue::from_value(&v) { Some(x) => { x }, None => { return; } } ); } #[test] fn test_value_layout() { assert_eq!(mem::size_of::(), 4); assert_eq!(mem::size_of::(), 16); } #[test] fn test_abi() { let mut data = VALUE { t: VALUE_TYPE::T_UNDEFINED, u: 0, d: 0 }; assert_eq!(data.t, VALUE_TYPE::T_UNDEFINED); (_API.ValueInit)(&mut data); assert_eq!(data.t, VALUE_TYPE::T_UNDEFINED); (_API.ValueClear)(&mut data); assert_eq!(data.t, VALUE_TYPE::T_UNDEFINED); } }