diff --git a/packages/cubejs-backend-native/src/node_export.rs b/packages/cubejs-backend-native/src/node_export.rs index efe7446537d56..e511c42609141 100644 --- a/packages/cubejs-backend-native/src/node_export.rs +++ b/packages/cubejs-backend-native/src/node_export.rs @@ -577,13 +577,15 @@ pub fn reset_logger(mut cx: FunctionContext) -> JsResult { fn build_sql_and_params(cx: FunctionContext) -> JsResult { neon_run_with_guarded_lifetime(cx, |neon_context_holder| { - let options = - NativeObjectHandle::>>::new(NeonObject::new( + let options = NativeObjectHandle::>>::new( + NeonObject::new( neon_context_holder.clone(), neon_context_holder .with_context(|cx| cx.argument::(0)) .unwrap()?, - )); + ) + .unwrap(), + ); let safe_call_fn = neon_context_holder .with_context(|cx| { @@ -608,7 +610,7 @@ fn build_sql_and_params(cx: FunctionContext) -> JsResult { let res = base_query.build_sql_and_params(); let result: NeonObject> = res.into_object(); - let result = result.into_object(); + let result = result.get_object().unwrap(); Ok(result) }) } diff --git a/rust/cubenativeutils/src/wrappers/neon/context.rs b/rust/cubenativeutils/src/wrappers/neon/context.rs index 637fd30a56564..f133090dd9928 100644 --- a/rust/cubenativeutils/src/wrappers/neon/context.rs +++ b/rust/cubenativeutils/src/wrappers/neon/context.rs @@ -229,17 +229,17 @@ impl + 'static> NativeContext> for Context let obj = NeonObject::new( self.clone(), self.with_context(|cx| cx.boolean(v).upcast())?, - ); + )?; obj.into_boolean() } fn string(&self, v: String) -> Result, CubeError> { - let obj = NeonObject::new(self.clone(), self.with_context(|cx| cx.string(v).upcast())?); + let obj = NeonObject::new(self.clone(), self.with_context(|cx| cx.string(v).upcast())?)?; obj.into_string() } fn number(&self, v: f64) -> Result, CubeError> { - let obj = NeonObject::new(self.clone(), self.with_context(|cx| cx.number(v).upcast())?); + let obj = NeonObject::new(self.clone(), self.with_context(|cx| cx.number(v).upcast())?)?; obj.into_number() } @@ -247,21 +247,21 @@ impl + 'static> NativeContext> for Context Ok(NativeObjectHandle::new(NeonObject::new( self.clone(), self.with_context(|cx| cx.undefined().upcast())?, - ))) + )?)) } fn null(&self) -> Result>, CubeError> { Ok(NativeObjectHandle::new(NeonObject::new( self.clone(), self.with_context(|cx| cx.null().upcast())?, - ))) + )?)) } fn empty_array(&self) -> Result, CubeError> { let obj = NeonObject::new( self.clone(), self.with_context(|cx| cx.empty_array().upcast())?, - ); + )?; obj.into_array() } @@ -269,7 +269,7 @@ impl + 'static> NativeContext> for Context let obj = NeonObject::new( self.clone(), self.with_context(|cx| cx.empty_object().upcast())?, - ); + )?; obj.into_struct() } fn to_string_fn(&self, result: String) -> Result, CubeError> { @@ -280,7 +280,7 @@ impl + 'static> NativeContext> for Context .unwrap() .upcast() })?, - ); + )?; obj.into_function() } } diff --git a/rust/cubenativeutils/src/wrappers/neon/object/base_types.rs b/rust/cubenativeutils/src/wrappers/neon/object/base_types.rs index 2889f970875a5..8019c25034aff 100644 --- a/rust/cubenativeutils/src/wrappers/neon/object/base_types.rs +++ b/rust/cubenativeutils/src/wrappers/neon/object/base_types.rs @@ -1,82 +1,84 @@ -use super::{NeonObject, NeonTypeHandle}; +use super::primitive_root_holder::*; +use super::{NeonObject, RootHolder}; use crate::wrappers::neon::inner_types::NeonInnerTypes; -use std::marker::PhantomData; -use crate::wrappers::object::{NativeBoolean, NativeBox, NativeNumber, NativeString, NativeType}; +use crate::wrappers::object::{NativeBoolean, NativeNumber, NativeString, NativeType}; use cubesql::CubeError; use neon::prelude::*; -use std::ops::Deref; pub struct NeonString> { - object: NeonTypeHandle, + holder: PrimitiveNeonTypeHolder, } impl> NeonString { - pub fn new(object: NeonTypeHandle) -> Self { - Self { object } + pub fn new(holder: PrimitiveNeonTypeHolder) -> Self { + Self { holder } } } impl + 'static> NativeType> for NeonString { fn into_object(self) -> NeonObject { - self.object.upcast() + let root_holder = RootHolder::from_typed(self.holder); + NeonObject::form_root(root_holder) } } impl + 'static> NativeString> for NeonString { fn value(&self) -> Result { - self.object + self.holder .map_neon_object::<_, _>(|cx, object| Ok(object.value(cx)))? } } pub struct NeonNumber> { - object: NeonTypeHandle, + holder: PrimitiveNeonTypeHolder, } impl> NeonNumber { - pub fn new(object: NeonTypeHandle) -> Self { - Self { object } + pub fn new(holder: PrimitiveNeonTypeHolder) -> Self { + Self { holder } } } impl + 'static> NativeType> for NeonNumber { fn into_object(self) -> NeonObject { - self.object.upcast() + let root_holder = RootHolder::from_typed(self.holder); + NeonObject::form_root(root_holder) } } impl + 'static> NativeNumber> for NeonNumber { fn value(&self) -> Result { - self.object + self.holder .map_neon_object::<_, _>(|cx, object| Ok(object.value(cx)))? } } pub struct NeonBoolean> { - object: NeonTypeHandle, + holder: PrimitiveNeonTypeHolder, } impl> NeonBoolean { - pub fn new(object: NeonTypeHandle) -> Self { - Self { object } + pub fn new(holder: PrimitiveNeonTypeHolder) -> Self { + Self { holder } } } impl + 'static> NativeType> for NeonBoolean { fn into_object(self) -> NeonObject { - self.object.upcast() + let root_holder = RootHolder::from_typed(self.holder); + NeonObject::form_root(root_holder) } } impl + 'static> NativeBoolean> for NeonBoolean { fn value(&self) -> Result { - self.object + self.holder .map_neon_object::<_, _>(|cx, object| Ok(object.value(cx)))? } } -pub struct NeonBox, T: 'static> { +/* pub struct NeonBox, T: 'static> { object: NeonTypeHandle>, _marker: PhantomData, } @@ -100,4 +102,4 @@ impl + 'static, T: 'static> NativeBox, T> fn deref_value(&self) -> &T { self.object.get_object_ref().deref() } -} +} */ diff --git a/rust/cubenativeutils/src/wrappers/neon/object/mod.rs b/rust/cubenativeutils/src/wrappers/neon/object/mod.rs index 4f404bec2866a..f3fdd636a2064 100644 --- a/rust/cubenativeutils/src/wrappers/neon/object/mod.rs +++ b/rust/cubenativeutils/src/wrappers/neon/object/mod.rs @@ -1,186 +1,13 @@ pub mod base_types; pub mod neon_array; pub mod neon_function; +pub mod neon_object; pub mod neon_struct; - -use self::{ - base_types::{NeonBoolean, NeonNumber, NeonString}, - neon_array::NeonArray, - neon_function::NeonFunction, - neon_struct::NeonStruct, -}; -use super::inner_types::NeonInnerTypes; -use crate::wrappers::{ - neon::context::{ContextHolder, SafeCallFn}, - object::NativeObject, -}; -use cubesql::CubeError; -use neon::prelude::*; - -pub struct NeonTypeHandle, V: Value + 'static> { - context: ContextHolder, - object: Handle<'static, V>, -} - -impl + 'static, V: Value + 'static> NeonTypeHandle { - pub fn new(context: ContextHolder, object: Handle<'static, V>) -> Self { - Self { context, object } - } - - fn get_context(&self) -> ContextHolder { - self.context.clone() - } - - pub fn get_object(&self) -> Handle<'static, V> { - self.object - } - - pub fn get_object_ref(&self) -> &Handle<'static, V> { - &self.object - } - - pub fn into_object(self) -> Handle<'static, V> { - self.object - } - - pub fn upcast(&self) -> NeonObject { - NeonObject::new(self.context.clone(), self.object.upcast()) - } - - pub fn map_neon_object(&self, f: F) -> Result - where - F: FnOnce(&mut C, &Handle<'static, V>) -> T, - { - self.context.with_context(|cx| f(cx, &self.object)) - } - - pub fn map_downcast_neon_object(&self, f: F) -> Result - where - F: FnOnce(&mut C, &Handle<'static, JT>) -> Result, - { - self.context.with_context(|cx| { - let obj = self - .object - .downcast::(cx) - .map_err(|_| CubeError::internal("Downcast error".to_string()))?; - f(cx, &obj) - })? - } - - pub fn map_neon_object_with_safe_call_fn(&self, f: F) -> Result - where - F: FnOnce(&mut C, &Handle<'static, V>, SafeCallFn) -> T, - { - self.context - .with_context_and_safe_fn(|cx, safe_call_fn| f(cx, &self.object, safe_call_fn)) - } - - pub fn is_a(&self) -> Result { - self.context.with_context(|cx| self.object.is_a::(cx)) - } -} - -impl, V: Value + 'static> Clone for NeonTypeHandle { - fn clone(&self) -> Self { - Self { - context: self.context.clone(), - object: self.object, - } - } -} - -pub struct NeonObject> { - context: ContextHolder, - object: Handle<'static, JsValue>, -} - -impl + 'static> NeonObject { - pub fn new(context: ContextHolder, object: Handle<'static, JsValue>) -> Self { - Self { context, object } - } - - pub fn get_object(&self) -> Handle<'static, JsValue> { - self.object - } - - pub fn get_object_ref(&self) -> &Handle<'static, JsValue> { - &self.object - } - - pub fn into_object(self) -> Handle<'static, JsValue> { - self.object - } - - pub fn is_a(&self) -> Result { - self.context.with_context(|cx| self.object.is_a::(cx)) - } - - pub fn downcast(&self) -> Result, CubeError> { - let obj = self.context.with_context(|cx| { - self.object - .downcast::(cx) - .map_err(|_| CubeError::internal("Downcast error".to_string())) - })??; - Ok(NeonTypeHandle::new(self.context.clone(), obj)) - } - - pub fn downcast_with_err_msg( - &self, - msg: &str, - ) -> Result, CubeError> { - let obj = self.context.with_context(|cx| { - self.object - .downcast::(cx) - .map_err(|_| CubeError::internal(msg.to_string())) - })??; - Ok(NeonTypeHandle::new(self.context.clone(), obj)) - } -} - -impl + 'static> NativeObject> for NeonObject { - fn get_context(&self) -> ContextHolder { - self.context.clone() - } - - fn into_struct(self) -> Result, CubeError> { - let obj = self.downcast_with_err_msg::("NeonObject is not the JsObject")?; - Ok(NeonStruct::new(obj)) - } - fn into_function(self) -> Result, CubeError> { - let obj = self.downcast_with_err_msg::("NeonObject is not the JsArray")?; - Ok(NeonFunction::new(obj)) - } - fn into_array(self) -> Result, CubeError> { - let obj = self.downcast_with_err_msg::("NeonObject is not the JsArray")?; - Ok(NeonArray::new(obj)) - } - fn into_string(self) -> Result, CubeError> { - let obj = self.downcast_with_err_msg::("NeonObject is not the JsString")?; - Ok(NeonString::new(obj)) - } - fn into_number(self) -> Result, CubeError> { - let obj = self.downcast_with_err_msg::("NeonObject is not the JsNumber")?; - Ok(NeonNumber::new(obj)) - } - fn into_boolean(self) -> Result, CubeError> { - let obj = self.downcast_with_err_msg::("NeonObject is not the JsBoolean")?; - Ok(NeonBoolean::new(obj)) - } - - fn is_null(&self) -> Result { - self.is_a::() - } - - fn is_undefined(&self) -> Result { - self.is_a::() - } -} - -impl> Clone for NeonObject { - fn clone(&self) -> Self { - Self { - context: self.context.clone(), - object: self.object, - } - } -} +pub mod object_root_holder; +pub mod primitive_root_holder; +pub mod root_holder; + +pub use neon_object::*; +use object_root_holder::*; +use primitive_root_holder::*; +use root_holder::*; diff --git a/rust/cubenativeutils/src/wrappers/neon/object/neon_array.rs b/rust/cubenativeutils/src/wrappers/neon/object/neon_array.rs index 08dea2a0c1ee0..fa8d74e105d48 100644 --- a/rust/cubenativeutils/src/wrappers/neon/object/neon_array.rs +++ b/rust/cubenativeutils/src/wrappers/neon/object/neon_array.rs @@ -1,4 +1,4 @@ -use super::{NeonObject, NeonTypeHandle}; +use super::{NeonObject, ObjectNeonTypeHolder, RootHolder}; use crate::wrappers::{ neon::inner_types::NeonInnerTypes, object::{NativeArray, NativeType}, @@ -7,20 +7,28 @@ use crate::wrappers::{ use cubesql::CubeError; use neon::prelude::*; -#[derive(Clone)] pub struct NeonArray> { - object: NeonTypeHandle, + object: ObjectNeonTypeHolder, } impl + 'static> NeonArray { - pub fn new(object: NeonTypeHandle) -> Self { + pub fn new(object: ObjectNeonTypeHolder) -> Self { Self { object } } } +impl> Clone for NeonArray { + fn clone(&self) -> Self { + Self { + object: self.object.clone(), + } + } +} + impl + 'static> NativeType> for NeonArray { fn into_object(self) -> NeonObject { - self.object.upcast() + let root_holder = RootHolder::from_typed(self.object); + NeonObject::form_root(root_holder) } } @@ -36,17 +44,22 @@ impl + 'static> NativeArray> for NeonArray .map_err(|_| CubeError::internal("Error converting JsArray to Vec".to_string())) })??; - Ok(neon_vec + neon_vec .into_iter() - .map(|o| NativeObjectHandle::new(NeonObject::new(self.object.get_context(), o))) - .collect()) + .map(|o| -> Result<_, CubeError> { + Ok(NativeObjectHandle::new(NeonObject::new( + self.object.get_context(), + o, + )?)) + }) + .collect::, _>>() } fn set( &self, index: u32, value: NativeObjectHandle>, ) -> Result { - let value = value.into_object().into_object(); + let value = value.into_object().get_object()?; self.object.map_neon_object::<_, _>(|cx, object| { object .set(cx, index, value) @@ -62,6 +75,6 @@ impl + 'static> NativeArray> for NeonArray Ok(NativeObjectHandle::new(NeonObject::new( self.object.get_context(), r, - ))) + )?)) } } diff --git a/rust/cubenativeutils/src/wrappers/neon/object/neon_function.rs b/rust/cubenativeutils/src/wrappers/neon/object/neon_function.rs index 79829631c5cab..e6adba75c7f55 100644 --- a/rust/cubenativeutils/src/wrappers/neon/object/neon_function.rs +++ b/rust/cubenativeutils/src/wrappers/neon/object/neon_function.rs @@ -1,4 +1,4 @@ -use super::{NeonObject, NeonTypeHandle}; +use super::{NeonObject, ObjectNeonTypeHolder, RootHolder}; use crate::wrappers::{ neon::inner_types::NeonInnerTypes, object::{NativeFunction, NativeType}, @@ -9,20 +9,28 @@ use lazy_static::lazy_static; use neon::prelude::*; use regex::Regex; -#[derive(Clone)] pub struct NeonFunction> { - object: NeonTypeHandle, + object: ObjectNeonTypeHolder, } impl + 'static> NeonFunction { - pub fn new(object: NeonTypeHandle) -> Self { + pub fn new(object: ObjectNeonTypeHolder) -> Self { Self { object } } } +impl> Clone for NeonFunction { + fn clone(&self) -> Self { + Self { + object: self.object.clone(), + } + } +} + impl + 'static> NativeType> for NeonFunction { fn into_object(self) -> NeonObject { - self.object.upcast() + let root_holder = RootHolder::from_typed(self.object); + NeonObject::form_root(root_holder) } } @@ -33,7 +41,7 @@ impl + 'static> NativeFunction> for NeonFu ) -> Result>, CubeError> { let neon_args = args .into_iter() - .map(|arg| -> Result<_, CubeError> { Ok(arg.into_object().get_object()) }) + .map(|arg| -> Result<_, CubeError> { arg.into_object().get_object() }) .collect::, _>>()?; let neon_reuslt = self.object @@ -42,9 +50,9 @@ impl + 'static> NativeFunction> for NeonFu safe_call_fn.safe_call(cx, neon_object, null, neon_args) })??; Ok(NativeObjectHandle::new(NeonObject::new( - self.object.context.clone(), + self.object.get_context(), neon_reuslt, - ))) + )?)) } fn definition(&self) -> Result { diff --git a/rust/cubenativeutils/src/wrappers/neon/object/neon_object.rs b/rust/cubenativeutils/src/wrappers/neon/object/neon_object.rs new file mode 100644 index 0000000000000..e0c3cca04aa13 --- /dev/null +++ b/rust/cubenativeutils/src/wrappers/neon/object/neon_object.rs @@ -0,0 +1,104 @@ +use super::{ + base_types::{NeonBoolean, NeonNumber, NeonString}, + neon_array::NeonArray, + neon_function::NeonFunction, + neon_struct::NeonStruct, + RootHolder, +}; +use crate::wrappers::neon::{context::ContextHolder, inner_types::NeonInnerTypes}; +use crate::wrappers::object::NativeObject; +use cubesql::CubeError; +use neon::prelude::*; + +pub struct NeonObject + 'static> { + root_holder: RootHolder, +} + +impl + 'static> NeonObject { + pub fn new( + context: ContextHolder, + object: Handle<'static, JsValue>, + ) -> Result { + let root_holder = RootHolder::new(context.clone(), object)?; + Ok(Self { root_holder }) + } + + pub fn form_root(root: RootHolder) -> Self { + Self { root_holder: root } + } + + pub fn get_object(&self) -> Result, CubeError> { + match &self.root_holder { + RootHolder::Null(v) => v.map_neon_object(|_cx, obj| Ok(obj.upcast())), + RootHolder::Undefined(v) => v.map_neon_object(|_cx, obj| Ok(obj.upcast())), + RootHolder::Boolean(v) => v.map_neon_object(|_cx, obj| Ok(obj.upcast())), + RootHolder::Number(v) => v.map_neon_object(|_cx, obj| Ok(obj.upcast())), + RootHolder::String(v) => v.map_neon_object(|_cx, obj| Ok(obj.upcast())), + RootHolder::Array(v) => v.map_neon_object(|_cx, obj| Ok(obj.upcast())), + RootHolder::Function(v) => v.map_neon_object(|_cx, obj| Ok(obj.upcast())), + RootHolder::Struct(v) => v.map_neon_object(|_cx, obj| Ok(obj.upcast())), + }? + } + + pub fn is_a(&self) -> Result { + let obj = self.get_object()?; + self.root_holder + .get_context() + .with_context(|cx| obj.is_a::(cx)) + } + + pub fn is_null(&self) -> bool { + matches!(self.root_holder, RootHolder::Null(_)) + } + + pub fn is_undefined(&self) -> bool { + matches!(self.root_holder, RootHolder::Undefined(_)) + } +} + +impl + 'static> NativeObject> for NeonObject { + fn get_context(&self) -> ContextHolder { + self.root_holder.get_context() + } + + fn into_struct(self) -> Result, CubeError> { + let obj_holder = self.root_holder.into_struct()?; + Ok(NeonStruct::new(obj_holder)) + } + fn into_function(self) -> Result, CubeError> { + let obj_holder = self.root_holder.into_function()?; + Ok(NeonFunction::new(obj_holder)) + } + fn into_array(self) -> Result, CubeError> { + let obj_holder = self.root_holder.into_array()?; + Ok(NeonArray::new(obj_holder)) + } + fn into_string(self) -> Result, CubeError> { + let holder = self.root_holder.into_string()?; + Ok(NeonString::new(holder)) + } + fn into_number(self) -> Result, CubeError> { + let holder = self.root_holder.into_number()?; + Ok(NeonNumber::new(holder)) + } + fn into_boolean(self) -> Result, CubeError> { + let holder = self.root_holder.into_boolean()?; + Ok(NeonBoolean::new(holder)) + } + + fn is_null(&self) -> Result { + Ok(self.is_null()) + } + + fn is_undefined(&self) -> Result { + Ok(self.is_undefined()) + } +} + +impl + 'static> Clone for NeonObject { + fn clone(&self) -> Self { + Self { + root_holder: self.root_holder.clone(), + } + } +} diff --git a/rust/cubenativeutils/src/wrappers/neon/object/neon_struct.rs b/rust/cubenativeutils/src/wrappers/neon/object/neon_struct.rs index 7f835698642fe..6a0bf06d9c523 100644 --- a/rust/cubenativeutils/src/wrappers/neon/object/neon_struct.rs +++ b/rust/cubenativeutils/src/wrappers/neon/object/neon_struct.rs @@ -1,4 +1,4 @@ -use super::{NeonObject, NeonTypeHandle}; +use super::{NeonObject, ObjectNeonTypeHolder, RootHolder}; use crate::wrappers::{ neon::inner_types::NeonInnerTypes, object::{NativeStruct, NativeType}, @@ -7,20 +7,28 @@ use crate::wrappers::{ use cubesql::CubeError; use neon::prelude::*; -#[derive(Clone)] pub struct NeonStruct> { - object: NeonTypeHandle, + object: ObjectNeonTypeHolder, } impl + 'static> NeonStruct { - pub fn new(object: NeonTypeHandle) -> Self { + pub fn new(object: ObjectNeonTypeHolder) -> Self { Self { object } } } +impl> Clone for NeonStruct { + fn clone(&self) -> Self { + Self { + object: self.object.clone(), + } + } +} + impl + 'static> NativeType> for NeonStruct { fn into_object(self) -> NeonObject { - self.object.upcast() + let root_holder = RootHolder::from_typed(self.object); + NeonObject::form_root(root_holder) } } @@ -35,9 +43,9 @@ impl + 'static> NativeStruct> for NeonStru .map_err(|_| CubeError::internal(format!("Field `{}` not found", field_name))) })??; Ok(NativeObjectHandle::new(NeonObject::new( - self.object.context.clone(), + self.object.get_context(), neon_result, - ))) + )?)) } fn has_field(&self, field_name: &str) -> Result { @@ -63,7 +71,7 @@ impl + 'static> NativeStruct> for NeonStru field_name: &str, value: NativeObjectHandle>, ) -> Result { - let value = value.into_object().into_object(); + let value = value.into_object().get_object()?; self.object.map_neon_object::<_, _>(|cx, object| { object .set(cx, field_name, value) @@ -82,10 +90,10 @@ impl + 'static> NativeStruct> for NeonStru .to_vec(cx) .map_err(|_| CubeError::internal("Failed to convert array".to_string())) })??; - Ok(neon_array + neon_array .into_iter() - .map(|o| NativeObjectHandle::new(NeonObject::new(self.object.context.clone(), o))) - .collect()) + .map(|o| NeonObject::new(self.object.get_context(), o).map(NativeObjectHandle::new)) + .collect::, _>>() } fn call_method( &self, @@ -94,7 +102,7 @@ impl + 'static> NativeStruct> for NeonStru ) -> Result>, CubeError> { let neon_args = args .into_iter() - .map(|arg| -> Result<_, CubeError> { Ok(arg.into_object().get_object()) }) + .map(|arg| -> Result<_, CubeError> { arg.into_object().get_object() }) .collect::, _>>()?; let neon_reuslt = @@ -109,8 +117,8 @@ impl + 'static> NativeStruct> for NeonStru safe_call_fn.safe_call(cx, &neon_method, *neon_object, neon_args) })??; Ok(NativeObjectHandle::new(NeonObject::new( - self.object.context.clone(), + self.object.get_context(), neon_reuslt, - ))) + )?)) } } diff --git a/rust/cubenativeutils/src/wrappers/neon/object/object_root_holder.rs b/rust/cubenativeutils/src/wrappers/neon/object/object_root_holder.rs new file mode 100644 index 0000000000000..2f74b4b43f4e1 --- /dev/null +++ b/rust/cubenativeutils/src/wrappers/neon/object/object_root_holder.rs @@ -0,0 +1,73 @@ +use crate::wrappers::neon::context::{ContextHolder, SafeCallFn}; +use cubesql::CubeError; +use neon::prelude::*; +use std::rc::Rc; + +pub struct ObjectNeonTypeHolder, V: Object + 'static> { + context: ContextHolder, + value: Option>>, +} +impl + 'static, V: Object + 'static> ObjectNeonTypeHolder { + pub fn new(context: ContextHolder, object: Handle<'static, V>, cx: &mut C) -> Self { + let value = object.root(cx); + Self { + context, + value: Some(Rc::new(value)), + } + } + + pub fn get_context(&self) -> ContextHolder { + self.context.clone() + } + + fn value_ref(&self) -> &Root { + // Invariant: `self.value` must always be `Some` between construction and `Drop`. + // If it's `None` here, it means the object is in an invalid state (e.g. accessed during destruction), + // which is a bug. `unwrap()` is used to enforce this contract by panicking early. + self.value.as_ref().unwrap() + } + + pub fn map_neon_object(&self, f: F) -> Result + where + F: FnOnce(&mut C, &Handle<'static, V>) -> T, + { + self.context.with_context(|cx| { + let object = self.value_ref().to_inner(cx); + f(cx, &object) + }) + } + + pub fn map_neon_object_with_safe_call_fn(&self, f: F) -> Result + where + F: FnOnce(&mut C, &Handle<'static, V>, SafeCallFn) -> T, + { + self.context.with_context_and_safe_fn(|cx, safe_call_fn| { + let object = self.value_ref().to_inner(cx); + f(cx, &object, safe_call_fn) + }) + } +} + +impl, V: Object + 'static> Drop for ObjectNeonTypeHolder { + fn drop(&mut self) { + if let Some(value) = self.value.take() { + if let Ok(value) = Rc::try_unwrap(value) { + let res = self.context.with_context(|cx| { + value.drop(cx); + }); + if let Err(e) = res { + log::error!("Error while dropping Neon Root: {}", e) + } + } + } + } +} + +impl, V: Object + 'static> Clone for ObjectNeonTypeHolder { + fn clone(&self) -> Self { + Self { + context: self.context.clone(), + value: self.value.clone(), + } + } +} diff --git a/rust/cubenativeutils/src/wrappers/neon/object/primitive_root_holder.rs b/rust/cubenativeutils/src/wrappers/neon/object/primitive_root_holder.rs new file mode 100644 index 0000000000000..45f485de08569 --- /dev/null +++ b/rust/cubenativeutils/src/wrappers/neon/object/primitive_root_holder.rs @@ -0,0 +1,161 @@ +use crate::wrappers::neon::context::{ContextHolder, SafeCallFn}; +use cubesql::CubeError; +use neon::prelude::*; + +pub trait NeonPrimitiveMapping: Value { + type NativeType: Clone; + fn from_neon + 'static>( + cx: &mut C, + value: &Handle<'static, Self>, + ) -> Self::NativeType; + fn to_neon + 'static>( + cx: &mut C, + value: &Self::NativeType, + ) -> Handle<'static, Self>; + + fn is_null(&self) -> bool { + false + } + fn is_undefined(&self) -> bool { + false + } +} + +impl NeonPrimitiveMapping for JsBoolean { + type NativeType = bool; + fn from_neon + 'static>( + cx: &mut C, + value: &Handle<'static, Self>, + ) -> Self::NativeType { + value.value(cx) + } + + fn to_neon + 'static>( + cx: &mut C, + value: &Self::NativeType, + ) -> Handle<'static, Self> { + cx.boolean(value.clone()) + } +} + +impl NeonPrimitiveMapping for JsNumber { + type NativeType = f64; + fn from_neon + 'static>( + cx: &mut C, + value: &Handle<'static, Self>, + ) -> Self::NativeType { + value.value(cx) + } + fn to_neon + 'static>( + cx: &mut C, + value: &Self::NativeType, + ) -> Handle<'static, Self> { + cx.number(value.clone()) + } +} + +impl NeonPrimitiveMapping for JsString { + type NativeType = String; + fn from_neon + 'static>( + cx: &mut C, + value: &Handle<'static, Self>, + ) -> Self::NativeType { + value.value(cx) + } + fn to_neon + 'static>( + cx: &mut C, + value: &Self::NativeType, + ) -> Handle<'static, Self> { + cx.string(value) + } +} + +impl NeonPrimitiveMapping for JsNull { + type NativeType = (); + fn from_neon + 'static>( + _cx: &mut C, + _value: &Handle<'static, Self>, + ) -> Self::NativeType { + } + fn to_neon + 'static>( + cx: &mut C, + _value: &Self::NativeType, + ) -> Handle<'static, Self> { + cx.null() + } + + fn is_null(&self) -> bool { + true + } +} + +impl NeonPrimitiveMapping for JsUndefined { + type NativeType = (); + fn from_neon + 'static>( + _cx: &mut C, + _value: &Handle<'static, Self>, + ) -> Self::NativeType { + } + fn to_neon + 'static>( + cx: &mut C, + _value: &Self::NativeType, + ) -> Handle<'static, Self> { + cx.undefined() + } + fn is_undefined(&self) -> bool { + false + } +} + +pub struct PrimitiveNeonTypeHolder, V: NeonPrimitiveMapping + 'static> { + context: ContextHolder, + value: V::NativeType, +} + +impl + 'static, V: Value + NeonPrimitiveMapping + 'static> + PrimitiveNeonTypeHolder +{ + pub fn new(context: ContextHolder, object: Handle<'static, V>, cx: &mut C) -> Self { + let value = V::from_neon(cx, &object); + Self { context, value } + } + + pub fn get_context(&self) -> ContextHolder { + self.context.clone() + } + + pub fn map_neon_object(&self, f: F) -> Result + where + F: FnOnce(&mut C, &Handle<'static, V>) -> T, + { + self.context.with_context(|cx| { + let object = V::to_neon(cx, &self.value); + f(cx, &object) + }) + } + + pub fn map_neon_object_with_safe_call_fn(&self, f: F) -> Result + where + F: FnOnce(&mut C, &Handle<'static, V>, SafeCallFn) -> T, + { + self.context.with_context_and_safe_fn(|cx, safe_call_fn| { + let object = V::to_neon(cx, &self.value); + f(cx, &object, safe_call_fn) + }) + } + + pub fn into_object(self) -> Result, CubeError> { + self.context.with_context(|cx| V::to_neon(cx, &self.value)) + } +} + +impl, V: NeonPrimitiveMapping + 'static> Clone + for PrimitiveNeonTypeHolder +{ + fn clone(&self) -> Self { + Self { + context: self.context.clone(), + value: self.value.clone(), + } + } +} diff --git a/rust/cubenativeutils/src/wrappers/neon/object/root_holder.rs b/rust/cubenativeutils/src/wrappers/neon/object/root_holder.rs new file mode 100644 index 0000000000000..6105f37a2398a --- /dev/null +++ b/rust/cubenativeutils/src/wrappers/neon/object/root_holder.rs @@ -0,0 +1,136 @@ +use super::{ObjectNeonTypeHolder, PrimitiveNeonTypeHolder}; +use crate::wrappers::neon::context::ContextHolder; +use cubesql::CubeError; +use neon::prelude::*; +pub trait Upcast + 'static> { + fn upcast(self) -> RootHolder; +} + +macro_rules! impl_upcast { + ($($holder:ty => $variant:ident),+ $(,)?) => { + $( + impl + 'static> Upcast for $holder { + fn upcast(self) -> RootHolder { + RootHolder::$variant(self) + } + } + )+ + }; +} + +macro_rules! match_js_value_type { + ($context:expr, $value:expr, $cx:expr, { + $($variant:ident => $js_type:ty => $holder_type:ident),+ $(,)? + }) => { + $( + if $value.is_a::<$js_type, _>($cx) { + let downcasted = $value + .downcast::<$js_type, _>($cx) + .map_err(|_| CubeError::internal("Downcast error".to_string()))?; + return Ok(RootHolder::$variant($holder_type::new( + $context.clone(), + downcasted, + $cx + ))); + } + )+ + }; +} + +macro_rules! define_into_method { + ($method_name:ident, $variant:ident, $holder_type:ty, $error_msg:expr) => { + pub fn $method_name(self) -> Result<$holder_type, CubeError> { + match self { + Self::$variant(v) => Ok(v), + _ => Err(CubeError::internal($error_msg.to_string())), + } + } + }; +} + +impl_upcast!( + PrimitiveNeonTypeHolder => Null, + PrimitiveNeonTypeHolder => Undefined, + PrimitiveNeonTypeHolder => Boolean, + PrimitiveNeonTypeHolder => Number, + PrimitiveNeonTypeHolder => String, + ObjectNeonTypeHolder => Array, + ObjectNeonTypeHolder => Function, + ObjectNeonTypeHolder => Struct, +); + +pub enum RootHolder + 'static> { + Null(PrimitiveNeonTypeHolder), + Undefined(PrimitiveNeonTypeHolder), + Boolean(PrimitiveNeonTypeHolder), + Number(PrimitiveNeonTypeHolder), + String(PrimitiveNeonTypeHolder), + Array(ObjectNeonTypeHolder), + Function(ObjectNeonTypeHolder), + Struct(ObjectNeonTypeHolder), +} + +impl + 'static> RootHolder { + pub fn new( + context: ContextHolder, + value: Handle<'static, JsValue>, + ) -> Result { + context.with_context(|cx| { + match_js_value_type!(context, value, cx, { + Null => JsNull => PrimitiveNeonTypeHolder, + Undefined => JsUndefined => PrimitiveNeonTypeHolder, + Boolean => JsBoolean => PrimitiveNeonTypeHolder, + Number => JsNumber => PrimitiveNeonTypeHolder, + String => JsString => PrimitiveNeonTypeHolder, + Array => JsArray => ObjectNeonTypeHolder, + Function => JsFunction => ObjectNeonTypeHolder, + Struct => JsObject => ObjectNeonTypeHolder, + }); + + Err(CubeError::internal(format!( + "Unsupported JsValue {:?}", + value + ))) + })? + } + pub fn from_typed>(typed_holder: T) -> Self { + T::upcast(typed_holder) + } + + pub fn get_context(&self) -> ContextHolder { + match self { + Self::Null(v) => v.get_context(), + Self::Undefined(v) => v.get_context(), + Self::Boolean(v) => v.get_context(), + Self::Number(v) => v.get_context(), + Self::String(v) => v.get_context(), + Self::Array(v) => v.get_context(), + Self::Function(v) => v.get_context(), + Self::Struct(v) => v.get_context(), + } + } + + define_into_method!(into_null, Null, PrimitiveNeonTypeHolder, "Object is not the Null object"); + define_into_method!(into_undefined, Undefined, PrimitiveNeonTypeHolder, "Object is not the Undefined object"); + define_into_method!(into_boolean, Boolean, PrimitiveNeonTypeHolder, "Object is not the Boolean object"); + define_into_method!(into_number, Number, PrimitiveNeonTypeHolder, "Object is not the Number object"); + define_into_method!(into_string, String, PrimitiveNeonTypeHolder, "Object is not the String object"); + define_into_method!(into_array, Array, ObjectNeonTypeHolder, "Object is not the Array object"); + define_into_method!(into_function, Function, ObjectNeonTypeHolder, "Object is not the Function object"); + define_into_method!(into_struct, Struct, ObjectNeonTypeHolder, "Object is not the Struct object"); +} + +impl + 'static> Clone for RootHolder { + fn clone(&self) -> Self { + match self { + Self::Null(v) => Self::Null(v.clone()), + Self::Undefined(v) => Self::Undefined(v.clone()), + Self::Boolean(v) => Self::Boolean(v.clone()), + Self::Number(v) => Self::Number(v.clone()), + Self::String(v) => Self::String(v.clone()), + Self::Array(v) => Self::Array(v.clone()), + Self::Function(v) => Self::Function(v.clone()), + Self::Struct(v) => Self::Struct(v.clone()), + } + } +} diff --git a/rust/cubenativeutils/src/wrappers/object_handler.rs b/rust/cubenativeutils/src/wrappers/object_handler.rs deleted file mode 100644 index 65298226ef2d4..0000000000000 --- a/rust/cubenativeutils/src/wrappers/object_handler.rs +++ /dev/null @@ -1,83 +0,0 @@ -use super::context::NativeContextHolder; -use super::object::{ - NativeArray, NativeBoolean, NativeNumber, NativeObject, NativeString, NativeStruct, -}; -use cubesql::CubeError; - -pub struct NativeObjectHandler { - object: Box, -} - -impl NativeObjectHandler { - pub fn new(object: Box) -> Self { - Self { object } - } - - pub fn object_ref(&self) -> &Box { - &self.object - } - - pub fn downcast_object_ref(&self) -> Option<&T> { - self.object.as_any().downcast_ref() - } - - pub fn into_object(self) -> Box { - self.object - } - - pub fn downcast_object(self) -> Result, CubeError> { - self.object - .into_any() - .downcast::() - .map_err(|_| CubeError::internal("Unable to downcast object".to_string())) - } - - pub fn into_struct(self) -> Result, CubeError> { - self.object.into_struct() - } - pub fn into_array(self) -> Result, CubeError> { - self.object.into_array() - } - pub fn into_string(self) -> Result, CubeError> { - self.object.into_string() - } - pub fn into_number(self) -> Result, CubeError> { - self.object.into_number() - } - pub fn into_boolean(self) -> Result, CubeError> { - self.object.into_boolean() - } - pub fn to_struct(&self) -> Result, CubeError> { - self.object.boxed_clone().into_struct() - } - pub fn to_array(&self) -> Result, CubeError> { - self.object.boxed_clone().into_array() - } - pub fn to_string(&self) -> Result, CubeError> { - self.object.boxed_clone().into_string() - } - pub fn to_number(&self) -> Result, CubeError> { - self.object.boxed_clone().into_number() - } - pub fn to_boolean(&self) -> Result, CubeError> { - self.object.boxed_clone().into_boolean() - } - pub fn is_null(&self) -> bool { - self.object.is_null() - } - pub fn is_undefined(&self) -> bool { - self.object.is_undefined() - } - - pub fn get_context(&self) -> Result { - self.object.get_context() - } -} - -impl Clone for NativeObjectHandler { - fn clone(&self) -> Self { - Self { - object: self.object.boxed_clone(), - } - } -} diff --git a/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs b/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs index a54dae7dc1f64..bf3c56c7e824c 100644 --- a/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs +++ b/rust/cubesqlplanner/cubesqlplanner/src/planner/filter/base_filter.rs @@ -808,6 +808,7 @@ impl BaseFilter { fn is_need_null_chek(&self, is_not: bool) -> bool { let contains_null = self.is_values_contains_null(); + if is_not { !contains_null } else {