1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

feat(napi): improve napi coverage (#16198)

This commit is contained in:
Divy Srivastava 2022-12-13 06:26:53 -08:00 committed by GitHub
parent 76a9df1ed8
commit ac4b5de656
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 202 additions and 166 deletions

View file

@ -3,6 +3,7 @@
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
use deno_runtime::deno_napi::*; use deno_runtime::deno_napi::*;
use libc::INT_MAX;
use v8::BackingStore; use v8::BackingStore;
use v8::UniqueRef; use v8::UniqueRef;
@ -36,9 +37,7 @@ macro_rules! check_arg_option {
fn napi_create_array(env: *mut Env, result: *mut napi_value) -> Result { fn napi_create_array(env: *mut Env, result: *mut napi_value) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
check_arg!(result); check_arg!(result);
*result = v8::Array::new(&mut env.scope(), 0).into();
let value = v8::Array::new(&mut env.scope(), 0);
*result = value.into();
Ok(()) Ok(())
} }
@ -50,9 +49,7 @@ fn napi_create_array_with_length(
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
check_arg!(result); check_arg!(result);
*result = v8::Array::new(&mut env.scope(), len).into();
let value = v8::Array::new(&mut env.scope(), len);
*result = value.into();
Ok(()) Ok(())
} }
@ -83,9 +80,7 @@ fn napi_create_bigint_int64(
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
check_arg!(result); check_arg!(result);
*result = v8::BigInt::new_from_i64(&mut env.scope(), value).into();
let value = v8::BigInt::new_from_i64(&mut env.scope(), value);
*result = value.into();
Ok(()) Ok(())
} }
@ -96,9 +91,8 @@ fn napi_create_bigint_uint64(
result: *mut napi_value, result: *mut napi_value,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value: v8::Local<v8::Value> = check_arg!(result);
v8::BigInt::new_from_u64(&mut env.scope(), value).into(); *result = v8::BigInt::new_from_u64(&mut env.scope(), value).into();
*result = value.into();
Ok(()) Ok(())
} }
@ -111,14 +105,26 @@ fn napi_create_bigint_words(
result: *mut napi_value, result: *mut napi_value,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value: v8::Local<v8::Value> = v8::BigInt::new_from_words( check_arg!(words);
check_arg!(result);
if word_count > INT_MAX as _ {
return Err(Error::InvalidArg);
}
match v8::BigInt::new_from_words(
&mut env.scope(), &mut env.scope(),
sign_bit, sign_bit,
std::slice::from_raw_parts(words, word_count), std::slice::from_raw_parts(words, word_count),
) ) {
.unwrap() Some(value) => {
.into(); *result = value.into();
*result = value.into(); }
None => {
return Err(Error::InvalidArg);
}
}
Ok(()) Ok(())
} }
@ -272,9 +278,8 @@ fn napi_create_double(
result: *mut napi_value, result: *mut napi_value,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value: v8::Local<v8::Value> = check_arg!(result);
v8::Number::new(&mut env.scope(), value).into(); *result = v8::Number::new(&mut env.scope(), value).into();
*result = value.into();
Ok(()) Ok(())
} }
@ -398,33 +403,29 @@ fn napi_create_external_buffer(
fn napi_create_function( fn napi_create_function(
env_ptr: *mut Env, env_ptr: *mut Env,
name: *const u8, name: *const u8,
length: isize, length: usize,
cb: napi_callback, cb: napi_callback,
cb_info: napi_callback_info, cb_info: napi_callback_info,
result: *mut napi_value, result: *mut napi_value,
) -> Result { ) -> Result {
let _: &mut Env = env_ptr.as_mut().ok_or(Error::InvalidArg)?; let _: &mut Env = env_ptr.as_mut().ok_or(Error::InvalidArg)?;
let name = match name.is_null() { check_arg!(result);
true => None, check_arg_option!(cb);
false => Some(name), check_arg!(name);
};
let name = name.map(|name| {
if length == -1 {
std::ffi::CStr::from_ptr(name as *const _).to_str().unwrap()
} else {
let name = std::slice::from_raw_parts(name, length as usize);
// If ends with NULL
if name[name.len() - 1] == 0 {
std::str::from_utf8(&name[0..name.len() - 1]).unwrap()
} else {
std::str::from_utf8(name).unwrap()
}
}
});
let function = create_function(env_ptr, name, cb, cb_info); if length > INT_MAX as _ {
let value: v8::Local<v8::Value> = function.into(); return Err(Error::InvalidArg);
*result = value.into(); }
let name = std::slice::from_raw_parts(name, length);
// If it ends with NULL
let name = if name[name.len() - 1] == 0 {
std::str::from_utf8_unchecked(&name[0..name.len() - 1])
} else {
std::str::from_utf8_unchecked(name)
};
*result = create_function(env_ptr, Some(name), cb, cb_info).into();
Ok(()) Ok(())
} }
@ -435,9 +436,20 @@ fn napi_create_int32(
result: *mut napi_value, result: *mut napi_value,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value: v8::Local<v8::Value> = check_arg!(result);
v8::Number::new(&mut env.scope(), value as f64).into(); *result = v8::Integer::new(&mut env.scope(), value).into();
*result = value.into(); Ok(())
}
#[napi_sym::napi_sym]
fn napi_create_uint32(
env: *mut Env,
value: u32,
result: *mut napi_value,
) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
check_arg!(result);
*result = v8::Integer::new_from_unsigned(&mut env.scope(), value).into();
Ok(()) Ok(())
} }
@ -448,9 +460,8 @@ fn napi_create_int64(
result: *mut napi_value, result: *mut napi_value,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value: v8::Local<v8::Value> = check_arg!(result);
v8::Number::new(&mut env.scope(), value as f64).into(); *result = v8::Number::new(&mut env.scope(), value as f64).into();
*result = value.into();
Ok(()) Ok(())
} }
@ -519,12 +530,20 @@ fn napi_create_reference(
fn napi_create_string_latin1( fn napi_create_string_latin1(
env: *mut Env, env: *mut Env,
string: *const u8, string: *const u8,
length: isize, length: usize,
result: *mut napi_value, result: *mut napi_value,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
if length > 0 {
check_arg!(string);
}
check_arg!(result);
let safe_len = (length == NAPI_AUTO_LENGTH) || length <= INT_MAX as _;
if !safe_len {
return Err(Error::InvalidArg);
}
let string = if length == -1 { let string = if length == NAPI_AUTO_LENGTH {
std::ffi::CStr::from_ptr(string as *const _) std::ffi::CStr::from_ptr(string as *const _)
.to_str() .to_str()
.unwrap() .unwrap()
@ -538,8 +557,7 @@ fn napi_create_string_latin1(
v8::NewStringType::Normal, v8::NewStringType::Normal,
) { ) {
Some(v8str) => { Some(v8str) => {
let value: v8::Local<v8::Value> = v8str.into(); *result = v8str.into();
*result = value.into();
} }
None => return Err(Error::GenericFailure), None => return Err(Error::GenericFailure),
} }
@ -555,15 +573,34 @@ fn napi_create_string_utf16(
result: *mut napi_value, result: *mut napi_value,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let string = std::slice::from_raw_parts(string, length); if length > 0 {
let v8str = v8::String::new_from_two_byte( check_arg!(string);
}
check_arg!(result);
let safe_len = (length == NAPI_AUTO_LENGTH) || length <= INT_MAX as _;
if !safe_len {
return Err(Error::InvalidArg);
}
let string = if length == NAPI_AUTO_LENGTH {
let s = std::ffi::CStr::from_ptr(string as *const _)
.to_str()
.unwrap();
std::slice::from_raw_parts(s.as_ptr() as *const u16, s.len())
} else {
std::slice::from_raw_parts(string, length)
};
match v8::String::new_from_two_byte(
&mut env.scope(), &mut env.scope(),
string, string,
v8::NewStringType::Normal, v8::NewStringType::Normal,
) ) {
.unwrap(); Some(v8str) => {
let value: v8::Local<v8::Value> = v8str.into(); *result = v8str.into();
*result = value.into(); }
None => return Err(Error::GenericFailure),
}
Ok(()) Ok(())
} }
@ -571,12 +608,20 @@ fn napi_create_string_utf16(
fn napi_create_string_utf8( fn napi_create_string_utf8(
env: *mut Env, env: *mut Env,
string: *const u8, string: *const u8,
length: isize, length: usize,
result: *mut napi_value, result: *mut napi_value,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
if length > 0 {
check_arg!(string);
}
check_arg!(result);
let safe_len = (length == NAPI_AUTO_LENGTH) || length <= INT_MAX as _;
if !safe_len {
return Err(Error::InvalidArg);
}
let string = if length == -1 { let string = if length == NAPI_AUTO_LENGTH {
std::ffi::CStr::from_ptr(string as *const _) std::ffi::CStr::from_ptr(string as *const _)
.to_str() .to_str()
.unwrap() .unwrap()
@ -585,8 +630,7 @@ fn napi_create_string_utf8(
std::str::from_utf8(string).unwrap() std::str::from_utf8(string).unwrap()
}; };
let v8str = v8::String::new(&mut env.scope(), string).unwrap(); let v8str = v8::String::new(&mut env.scope(), string).unwrap();
let value: v8::Local<v8::Value> = v8str.into(); *result = v8str.into();
*result = value.into();
Ok(()) Ok(())
} }
@ -598,16 +642,16 @@ fn napi_create_symbol(
result: *mut napi_value, result: *mut napi_value,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let description = match description.is_none() { check_arg!(result);
true => None,
false => Some( let scope = &mut env.scope();
transmute::<napi_value, v8::Local<v8::Value>>(description) let description = description
.to_string(&mut env.scope()) .map(|d| match d.to_string(scope) {
.unwrap(), Some(s) => Ok(s),
), None => Err(Error::StringExpected),
}; })
let sym = v8::Symbol::new(&mut env.scope(), description); .transpose()?;
*result = sym.into(); *result = v8::Symbol::new(scope, description).into();
Ok(()) Ok(())
} }
@ -707,19 +751,6 @@ fn napi_create_typedarray(
Ok(()) Ok(())
} }
#[napi_sym::napi_sym]
fn napi_create_uint32(
env: *mut Env,
value: u32,
result: *mut napi_value,
) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value: v8::Local<v8::Value> =
v8::Number::new(&mut env.scope(), value as f64).into();
*result = value.into();
Ok(())
}
#[napi_sym::napi_sym] #[napi_sym::napi_sym]
fn napi_make_callback( fn napi_make_callback(
env: *mut Env, env: *mut Env,
@ -1082,7 +1113,7 @@ fn napi_define_class(
) -> Result { ) -> Result {
let env: &mut Env = env_ptr.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env_ptr.as_mut().ok_or(Error::InvalidArg)?;
check_arg!(result); check_arg!(result);
// check_arg!(constructor as *const c_void); check_arg_option!(constructor);
if property_count > 0 { if property_count > 0 {
check_arg!(properties); check_arg!(properties);
@ -1151,21 +1182,6 @@ fn napi_define_class(
setter, setter,
accessor_property, accessor_property,
); );
// // TODO: use set_accessor & set_accessor_with_setter
// match (getter, setter) {
// (Some(getter), None) => {
// proto.set(name.into(), getter.into());
// }
// (Some(getter), Some(setter)) => {
// proto.set(name.into(), getter.into());
// proto.set(name.into(), setter.into());
// }
// (None, Some(setter)) => {
// proto.set(name.into(), setter.into());
// }
// (None, None) => unreachable!(),
// }
} else if method.is_some() { } else if method.is_some() {
let function = create_function_template(env_ptr, None, p.method, p.data); let function = create_function_template(env_ptr, None, p.method, p.data);
let proto = tpl.prototype_template(scope); let proto = tpl.prototype_template(scope);
@ -1236,19 +1252,23 @@ fn napi_delete_element(
#[napi_sym::napi_sym] #[napi_sym::napi_sym]
fn napi_delete_property( fn napi_delete_property(
env: *mut Env, env: *mut Env,
value: napi_value, object: napi_value,
key: napi_value, key: napi_value,
result: *mut bool, result: *mut bool,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value = transmute::<napi_value, v8::Local<v8::Value>>(value); check_arg_option!(key);
let obj = value.to_object(&mut env.scope()).unwrap(); check_arg!(result);
*result = obj
.delete( let scope = &mut env.scope();
&mut env.scope(), let object = object
transmute::<napi_value, v8::Local<v8::Value>>(key), .map(|o| o.to_object(scope))
) .flatten()
.unwrap_or(false); .ok_or(Error::InvalidArg)?;
*result = object
.delete(scope, key.unwrap_unchecked())
.ok_or(Error::GenericFailure)?;
Ok(()) Ok(())
} }
@ -1332,9 +1352,8 @@ fn napi_get_boolean(
result: *mut napi_value, result: *mut napi_value,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value: v8::Local<v8::Value> = check_arg!(result);
v8::Boolean::new(env.isolate(), value).into(); *result = v8::Boolean::new(env.isolate(), value).into();
*result = value.into();
Ok(()) Ok(())
} }
@ -1362,13 +1381,16 @@ fn napi_get_buffer_info(
#[napi_sym::napi_sym] #[napi_sym::napi_sym]
fn napi_get_cb_info( fn napi_get_cb_info(
_env: *mut Env, env: *mut Env,
cbinfo: napi_callback_info, cbinfo: napi_callback_info,
argc: *mut i32, argc: *mut i32,
argv: *mut napi_value, argv: *mut napi_value,
this_arg: *mut napi_value, this_arg: *mut napi_value,
cb_data: *mut *mut c_void, cb_data: *mut *mut c_void,
) -> Result { ) -> Result {
let _: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
check_arg!(cbinfo);
let cbinfo: &CallbackInfo = &*(cbinfo as *const CallbackInfo); let cbinfo: &CallbackInfo = &*(cbinfo as *const CallbackInfo);
let args = &*(cbinfo.args as *const v8::FunctionCallbackArguments); let args = &*(cbinfo.args as *const v8::FunctionCallbackArguments);
@ -1519,9 +1541,8 @@ fn napi_get_new_target(
#[napi_sym::napi_sym] #[napi_sym::napi_sym]
fn napi_get_null(env: *mut Env, result: *mut napi_value) -> Result { fn napi_get_null(env: *mut Env, result: *mut napi_value) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
check_arg!(result);
let value: v8::Local<v8::Value> = v8::null(env.isolate()).into(); *result = v8::null(env.isolate()).into();
*result = value.into();
Ok(()) Ok(())
} }
@ -1611,8 +1632,8 @@ fn napi_get_typedarray_info(
#[napi_sym::napi_sym] #[napi_sym::napi_sym]
fn napi_get_undefined(env: *mut Env, result: *mut napi_value) -> Result { fn napi_get_undefined(env: *mut Env, result: *mut napi_value) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value: v8::Local<v8::Value> = v8::undefined(env.isolate()).into(); check_arg!(result);
*result = value.into(); *result = v8::undefined(env.isolate()).into();
Ok(()) Ok(())
} }
@ -1662,25 +1683,23 @@ fn napi_has_own_property(
result: *mut bool, result: *mut bool,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value = transmute::<napi_value, v8::Local<v8::Value>>(object); check_arg_option!(key);
let object = value.to_object(&mut env.scope()).unwrap(); check_arg!(result);
let key = transmute::<napi_value, v8::Local<v8::Value>>(key); let scope = &mut env.scope();
if !key.is_name() { let object = object
return Err(Error::NameExpected); .map(|o| o.to_object(scope))
} .flatten()
.ok_or(Error::InvalidArg)?;
let maybe = object let key = key
.has_own_property( .map(v8::Local::<v8::Name>::try_from)
&mut env.scope(), .ok_or(Error::InvalidArg)?
v8::Local::<v8::Name>::try_from(key).unwrap(), .map_err(|_| Error::NameExpected)?;
)
.unwrap_or(false);
*result = maybe; *result = object
if !maybe { .has_own_property(scope, key)
return Err(Error::GenericFailure); .ok_or(Error::GenericFailure)?;
}
Ok(()) Ok(())
} }
@ -1688,19 +1707,23 @@ fn napi_has_own_property(
#[napi_sym::napi_sym] #[napi_sym::napi_sym]
fn napi_has_property( fn napi_has_property(
env: *mut Env, env: *mut Env,
value: napi_value, object: napi_value,
key: napi_value, key: napi_value,
result: *mut bool, result: *mut bool,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let value = transmute::<napi_value, v8::Local<v8::Value>>(value); check_arg_option!(key);
let obj = value.to_object(&mut env.scope()).unwrap(); check_arg!(result);
*result = obj
.has( let scope = &mut env.scope();
&mut env.scope(), let object = object
transmute::<napi_value, v8::Local<v8::Value>>(key), .map(|o| o.to_object(scope))
) .flatten()
.unwrap_or(false); .ok_or(Error::InvalidArg)?;
*result = object
.has(scope, key.unwrap_unchecked())
.ok_or(Error::GenericFailure)?;
Ok(()) Ok(())
} }
@ -2068,28 +2091,38 @@ fn napi_set_named_property(
fn napi_set_property( fn napi_set_property(
env: *mut Env, env: *mut Env,
object: napi_value, object: napi_value,
property: napi_value, key: napi_value,
value: napi_value, value: napi_value,
) -> Result { ) -> Result {
let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?; let env: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let object = transmute::<napi_value, v8::Local<v8::Value>>(object); check_arg_option!(key);
let object = object.to_object(&mut env.scope()).unwrap(); check_arg_option!(value);
let property = transmute::<napi_value, v8::Local<v8::Value>>(property);
let value = transmute::<napi_value, v8::Local<v8::Value>>(value); let scope = &mut env.scope();
object.set(&mut env.scope(), property, value).unwrap(); let object = object
.map(|o| o.to_object(scope))
.flatten()
.ok_or(Error::InvalidArg)?;
object
.set(scope, key.unwrap_unchecked(), value.unwrap_unchecked())
.ok_or(Error::GenericFailure)?;
Ok(()) Ok(())
} }
#[napi_sym::napi_sym] #[napi_sym::napi_sym]
fn napi_strict_equals( fn napi_strict_equals(
_env: *mut Env, env: *mut Env,
lhs: napi_value, lhs: napi_value,
rhs: napi_value, rhs: napi_value,
result: *mut bool, result: *mut bool,
) -> Result { ) -> Result {
let lhs = transmute::<napi_value, v8::Local<v8::Value>>(lhs); let _: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
let rhs = transmute::<napi_value, v8::Local<v8::Value>>(rhs); check_arg_option!(lhs);
*result = lhs.strict_equals(rhs); check_arg_option!(rhs);
*result = lhs.unwrap_unchecked().strict_equals(rhs.unwrap_unchecked());
Ok(()) Ok(())
} }
@ -2189,22 +2222,23 @@ pub fn get_value_type(value: v8::Local<v8::Value>) -> Option<napi_valuetype> {
#[napi_sym::napi_sym] #[napi_sym::napi_sym]
fn napi_typeof( fn napi_typeof(
_env: *mut Env, env: *mut Env,
value: napi_value, value: napi_value,
result: *mut napi_valuetype, result: *mut napi_valuetype,
) -> Result { ) -> Result {
if value.is_none() { let _: &mut Env = env.as_mut().ok_or(Error::InvalidArg)?;
*result = napi_undefined; check_arg_option!(value);
return Ok(()); check_arg!(result);
} match get_value_type(value.unwrap()) {
let value = transmute::<napi_value, v8::Local<v8::Value>>(value); Some(ty) => {
let ty = get_value_type(value); *result = ty;
if let Some(ty) = ty { }
*result = ty; None => {
Ok(()) return Err(Error::InvalidArg);
} else { }
Err(Error::InvalidArg) };
}
Ok(())
} }
#[napi_sym::napi_sym] #[napi_sym::napi_sym]

View file

@ -75,6 +75,8 @@ pub const napi_arraybuffer_expected: napi_status = 19;
pub const napi_detachable_arraybuffer_expected: napi_status = 20; pub const napi_detachable_arraybuffer_expected: napi_status = 20;
pub const napi_would_deadlock: napi_status = 21; pub const napi_would_deadlock: napi_status = 21;
pub const NAPI_AUTO_LENGTH: usize = usize::MAX;
thread_local! { thread_local! {
pub static MODULE: RefCell<Option<*const NapiModule>> = RefCell::new(None); pub static MODULE: RefCell<Option<*const NapiModule>> = RefCell::new(None);
pub static ASYNC_WORK_SENDER: RefCell<Option<mpsc::UnboundedSender<PendingNapiAsyncWork>>> = RefCell::new(None); pub static ASYNC_WORK_SENDER: RefCell<Option<mpsc::UnboundedSender<PendingNapiAsyncWork>>> = RefCell::new(None);