use std::{
error::Error,
fmt::{self, Debug},
};
use super::{private::ValueInternal, Value};
use crate::{
context::{internal::Env, Context},
handle::{internal::TransparentNoCopyWrapper, Handle, Managed},
object::Object,
result::{JsResult, ResultExt},
sys::{self, raw},
};
#[cfg_attr(docsrs, doc(cfg(feature = "napi-5")))]
#[derive(Debug)]
#[repr(transparent)]
pub struct JsDate(raw::Local);
impl Value for JsDate {}
unsafe impl TransparentNoCopyWrapper for JsDate {
type Inner = raw::Local;
fn into_inner(self) -> Self::Inner {
self.0
}
}
impl Managed for JsDate {
fn to_raw(&self) -> raw::Local {
self.0
}
fn from_raw(_: Env, h: raw::Local) -> Self {
JsDate(h)
}
}
#[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(feature = "napi-5")))]
pub struct DateError(DateErrorKind);
impl DateError {
pub fn kind(&self) -> DateErrorKind {
self.0
}
}
impl fmt::Display for DateError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(self.0.as_str())
}
}
impl Error for DateError {}
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(docsrs, doc(cfg(feature = "napi-5")))]
pub enum DateErrorKind {
Overflow,
Underflow,
}
impl DateErrorKind {
fn as_str(&self) -> &'static str {
match *self {
DateErrorKind::Overflow => "Date overflow",
DateErrorKind::Underflow => "Date underflow",
}
}
}
impl<'a, T: Value> ResultExt<Handle<'a, T>> for Result<Handle<'a, T>, DateError> {
fn or_throw<'b, C: Context<'b>>(self, cx: &mut C) -> JsResult<'a, T> {
self.or_else(|e| cx.throw_range_error(e.0.as_str()))
}
}
impl JsDate {
pub const MIN_VALUE: f64 = -8.64e15;
pub const MAX_VALUE: f64 = 8.64e15;
pub fn new<'a, C: Context<'a>, T: Into<f64>>(
cx: &mut C,
value: T,
) -> Result<Handle<'a, JsDate>, DateError> {
let env = cx.env().to_raw();
let time = value.into();
if time > JsDate::MAX_VALUE {
return Err(DateError(DateErrorKind::Overflow));
} else if time < JsDate::MIN_VALUE {
return Err(DateError(DateErrorKind::Underflow));
}
let local = unsafe { sys::date::new_date(env, time) };
let date = Handle::new_internal(JsDate(local));
Ok(date)
}
pub fn new_lossy<'a, C: Context<'a>, V: Into<f64>>(cx: &mut C, value: V) -> Handle<'a, JsDate> {
let env = cx.env().to_raw();
let local = unsafe { sys::date::new_date(env, value.into()) };
Handle::new_internal(JsDate(local))
}
pub fn value<'a, C: Context<'a>>(&self, cx: &mut C) -> f64 {
let env = cx.env().to_raw();
unsafe { sys::date::value(env, self.to_raw()) }
}
pub fn is_valid<'a, C: Context<'a>>(&self, cx: &mut C) -> bool {
let value = self.value(cx);
(JsDate::MIN_VALUE..=JsDate::MAX_VALUE).contains(&value)
}
}
impl ValueInternal for JsDate {
fn name() -> String {
"object".to_string()
}
fn is_typeof<Other: Value>(env: Env, other: &Other) -> bool {
unsafe { sys::tag::is_date(env.to_raw(), other.to_raw()) }
}
}
impl Object for JsDate {}