Skip to content

Commit

Permalink
Merge pull request #639 from neon-bindings/feat/date-api
Browse files Browse the repository at this point in the history
feat: impl Date API
  • Loading branch information
amilajack authored Jan 13, 2021
2 parents 5adcdba + 22a7ea9 commit 7a76945
Show file tree
Hide file tree
Showing 11 changed files with 362 additions and 25 deletions.
22 changes: 20 additions & 2 deletions crates/neon-runtime/src/napi/bindings/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,21 @@ mod napi4 {
});
}

#[cfg(feature = "napi-5")]
mod napi5 {
use super::super::types::*;

generate!(extern "C" {
fn create_date(env: Env, value: f64, result: *mut Value) -> Status;

fn get_date_value(env: Env, value: Value, result: *mut f64) -> Status;

fn is_date(env: Env, value: Value, result: *mut bool) -> Status;
});
}

#[cfg(feature = "napi-6")]
mod napi6 {
mod napi6 {
use super::super::types::*;

generate!(extern "C" {
Expand All @@ -271,12 +284,14 @@ mod napi6 {
key_conversion: KeyConversion,
result: *mut Value,
) -> Status;
});
});
}

pub(crate) use napi1::*;
#[cfg(feature = "napi-4")]
pub(crate) use napi4::*;
#[cfg(feature = "napi-5")]
pub(crate) use napi5::*;
#[cfg(feature = "napi-6")]
pub(crate) use napi6::*;

Expand Down Expand Up @@ -310,6 +325,9 @@ pub(crate) unsafe fn load(env: Env) -> Result<(), libloading::Error> {
#[cfg(feature = "napi-4")]
napi4::load(&host, version, 4)?;

#[cfg(feature = "napi-5")]
napi5::load(&host, version, 5)?;

#[cfg(feature = "napi-6")]
napi6::load(&host, version, 6)?;

Expand Down
28 changes: 28 additions & 0 deletions crates/neon-runtime/src/napi/date.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use std::mem::MaybeUninit;
use crate::napi::bindings as napi;
use crate::raw::{Env, Local};

/// Create a new date object
///
/// # Safety
///
/// `env` is a raw pointer. Please ensure it points to a napi_env that is valid for the current context.
pub unsafe fn new_date(env: Env, value: f64) -> Local {
let mut local = MaybeUninit::zeroed();
let status = napi::create_date(env, value, local.as_mut_ptr());
assert_eq!(status, napi::Status::Ok);
local.assume_init()
}

/// Get the value of a date object
///
/// # Safety
///
/// `env` is a raw pointer. Please ensure it points to a napi_env that is valid for the current context.
/// `Local` must be an NAPI value associated with the given `Env`
pub unsafe fn value(env: Env, p: Local) -> f64 {
let mut value = 0.0;
let status = napi::get_date_value(env, p, &mut value as *mut _);
assert_eq!(status, napi::Status::Ok);
return value;
}
2 changes: 2 additions & 0 deletions crates/neon-runtime/src/napi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub mod scope;
pub mod string;
pub mod tag;
pub mod reference;
#[cfg(feature = "napi-5")]
pub mod date;
#[cfg(feature = "napi-4")]
pub mod tsfn;

Expand Down
6 changes: 6 additions & 0 deletions crates/neon-runtime/src/napi/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,9 @@ pub unsafe extern "C" fn is_arraybuffer(env: Env, val: Local) -> bool {
assert_eq!(napi::is_arraybuffer(env, val, &mut result as *mut _), napi::Status::Ok);
result
}

pub unsafe extern "C" fn is_date(env: Env, val: Local) -> bool {
let mut result = false;
assert_eq!(napi::is_date(env, val, &mut result as *mut _), napi::Status::Ok);
result
}
41 changes: 25 additions & 16 deletions src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use handle::{Managed, Handle};
#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
use event::EventQueue;
use types::{JsValue, Value, JsObject, JsArray, JsFunction, JsBoolean, JsNumber, JsString, StringResult, JsNull, JsUndefined};
#[cfg(feature = "napi-5")]
use types::date::{JsDate, DateError};
#[cfg(feature = "napi-1")]
use types::boxed::{Finalize, JsBox};
use types::binary::{JsArrayBuffer, JsBuffer};
Expand All @@ -27,6 +29,7 @@ use object::class::Class;
use result::{NeonResult, JsResult, Throw};
#[cfg(feature = "napi-1")]
use smallvec::SmallVec;

use self::internal::{ContextInternal, Scope, ScopeMetadata};

#[repr(C)]
Expand Down Expand Up @@ -135,22 +138,22 @@ impl<'a> Lock<'a> {
}

/// An _execution context_, which provides context-sensitive access to the JavaScript engine. Most operations that interact with the engine require passing a reference to a context.
///
///
/// A context has a lifetime `'a`, which ensures the safety of handles managed by the JS garbage collector. All handles created during the lifetime of a context are kept alive for that duration and cannot outlive the context.
pub trait Context<'a>: ContextInternal<'a> {

/// Lock the JavaScript engine, returning an RAII guard that keeps the lock active as long as the guard is alive.
///
///
/// If this is not the currently active context (for example, if it was used to spawn a scoped context with `execute_scoped` or `compute_scoped`), this method will panic.
fn lock(&self) -> Lock<'_> {
self.check_active();
Lock::new(self.env())
}

/// Convenience method for locking the JavaScript engine and borrowing a single JS value's internals.
///
///
/// # Example:
///
///
/// ```no_run
/// # use neon::prelude::*;
/// # fn my_neon_function(mut cx: FunctionContext) -> JsResult<JsNumber> {
Expand All @@ -160,7 +163,7 @@ pub trait Context<'a>: ContextInternal<'a> {
/// # Ok(n)
/// # }
/// ```
///
///
/// Note: the borrowed value is required to be a reference to a handle instead of a handle
/// as a workaround for a [Rust compiler bug](https://github.com/rust-lang/rust/issues/29997).
/// We may be able to generalize this compatibly in the future when the Rust bug is fixed,
Expand All @@ -177,9 +180,9 @@ pub trait Context<'a>: ContextInternal<'a> {
}

/// Convenience method for locking the JavaScript engine and mutably borrowing a single JS value's internals.
///
///
/// # Example:
///
///
/// ```no_run
/// # use neon::prelude::*;
/// # fn my_neon_function(mut cx: FunctionContext) -> JsResult<JsUndefined> {
Expand All @@ -191,7 +194,7 @@ pub trait Context<'a>: ContextInternal<'a> {
/// # Ok(cx.undefined())
/// # }
/// ```
///
///
/// Note: the borrowed value is required to be a reference to a handle instead of a handle
/// as a workaround for a [Rust compiler bug](https://github.com/rust-lang/rust/issues/29997).
/// We may be able to generalize this compatibly in the future when the Rust bug is fixed,
Expand All @@ -208,9 +211,9 @@ pub trait Context<'a>: ContextInternal<'a> {
}

/// Executes a computation in a new memory management scope.
///
///
/// Handles created in the new scope are kept alive only for the duration of the computation and cannot escape.
///
///
/// This method can be useful for limiting the life of temporary values created during long-running computations, to prevent leaks.
fn execute_scoped<T, F>(&self, f: F) -> T
where F: for<'b> FnOnce(ExecuteContext<'b>) -> T
Expand All @@ -223,9 +226,9 @@ pub trait Context<'a>: ContextInternal<'a> {
}

/// Executes a computation in a new memory management scope and computes a single result value that outlives the computation.
///
///
/// Handles created in the new scope are kept alive only for the duration of the computation and cannot escape, with the exception of the result value, which is rooted in the outer context.
///
///
/// This method can be useful for limiting the life of temporary values created during long-running computations, to prevent leaks.
fn compute_scoped<V, F>(&self, f: F) -> JsResult<'a, V>
where V: Value,
Expand Down Expand Up @@ -264,14 +267,14 @@ pub trait Context<'a>: ContextInternal<'a> {
}

/// Convenience method for creating a `JsString` value.
///
///
/// If the string exceeds the limits of the JS engine, this method panics.
fn string<S: AsRef<str>>(&mut self, s: S) -> Handle<'a, JsString> {
JsString::new(self, s)
}

/// Convenience method for creating a `JsString` value.
///
///
/// If the string exceeds the limits of the JS engine, this method returns an `Err` value.
fn try_string<S: AsRef<str>>(&mut self, s: S) -> StringResult<'a> {
JsString::try_new(self, s)
Expand Down Expand Up @@ -313,6 +316,12 @@ pub trait Context<'a>: ContextInternal<'a> {
JsBuffer::new(self, size)
}

/// Convenience method for creating a `JsDate` value.
#[cfg(feature = "napi-5")]
fn date(&mut self, value: impl Into<f64>) -> Result<Handle<'a, JsDate>, DateError> {
JsDate::new(self, value)
}

/// Produces a handle to the JavaScript global object.
fn global(&mut self) -> Handle<'a, JsObject> {
JsObject::build(|out| {
Expand Down Expand Up @@ -367,7 +376,7 @@ pub trait Context<'a>: ContextInternal<'a> {
/// Convenience method for wrapping a value in a `JsBox`.
///
/// # Example:
///
///
/// ```rust
/// # use neon::prelude::*;
/// struct Point(usize, usize);
Expand Down Expand Up @@ -500,7 +509,7 @@ impl<'a, 'b> ContextInternal<'a> for ComputeContext<'a, 'b> {
impl<'a, 'b> Context<'a> for ComputeContext<'a, 'b> { }

/// A view of the JS engine in the context of a function call.
///
///
/// The type parameter `T` is the type of the `this`-binding.
pub struct CallContext<'a, T: This> {
scope: Scope<'a, raw::HandleScope>,
Expand Down
12 changes: 6 additions & 6 deletions src/handle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub trait Managed: Copy {

/// A safely rooted _handle_ to a JS value in memory that is managed by the garbage collector.
#[repr(C)]
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
pub struct Handle<'a, T: Managed + 'a> {
value: T,
phantom: PhantomData<&'a T>
Expand Down Expand Up @@ -99,17 +99,17 @@ impl<'a, F: Value, T: Value> JsResultExt<'a, T> for DowncastResult<'a, F, T> {
impl<'a, T: Value> Handle<'a, T> {

/// Safely upcast a handle to a supertype.
///
///
/// This method does not require an execution context because it only copies a handle.
pub fn upcast<U: Value + SuperType<T>>(&self) -> Handle<'a, U> {
Handle::new_internal(SuperType::upcast_internal(self.value))
}

#[cfg(feature = "legacy-runtime")]
/// Tests whether this value is an instance of the given type.
///
///
/// # Example:
///
///
/// ```no_run
/// # use neon::prelude::*;
/// # fn my_neon_function(mut cx: FunctionContext) -> JsResult<JsUndefined> {
Expand All @@ -126,9 +126,9 @@ impl<'a, T: Value> Handle<'a, T> {

#[cfg(feature = "napi-1")]
/// Tests whether this value is an instance of the given type.
///
///
/// # Example:
///
///
/// ```no_run
/// # use neon::prelude::*;
/// # fn my_neon_function(mut cx: FunctionContext) -> JsResult<JsUndefined> {
Expand Down
Loading

0 comments on commit 7a76945

Please sign in to comment.