pub enum Nullable<T> {
Null,
NonNull(T),
}Expand description
A value that can be null in JavaScript, but not undefined.
This is used to distinguish between values in JavaScript that can be
null (i.e. Nullable<T>) vs. those of which that can be undefined
(i.e. Option<T>).
Nullable<T> tries to be close in API surface to the standard
Option<T>, though with a much smaller API scope, and can be
transformed into and from Option<T> for free.
§Why a new type?
There are in the standard 2 different values that are “null coalescing”:
undefined, which is its own type (typeof void 0 == "undefined"),null, which is different fromundefined(undefined !== null) but is of type object (typeof null === "object") for legacy reasons.
Option<T> sets up the first case, so we needed to add a new type for
the second case.
§Would it be bad to use Option::<T>::None as both undefined or null?
Many values in the standard can be null but not undefined, or the other
way around. Coalescing these two into Option::None means that any
conversions using boa’s traits (such as TryFromJs) would result in
indistinguishable values. The only way to respect the standard in this case
would be to get JsValue and manually verify it’s not undefined/null, then
do the conversion. This new type makes this process much simpler.
It also means that there is an asymmetry between JsValue to Option<T>
then Option<T> back to JsValue, leading to unintuitive errors. Having
a type Nullable<T> that acts like Option<T> but (de-)serialize to
null clarifies all usage.
§How can I do EitherNullOrUndefined<T>?
The best way is to use Nullable<Option<T>> and convert into Option<T>
using Nullable::flatten(). Please note that the reverse
(Nullable<Option<T>>) results in the same deserializing behaviour but
does not implement flatten().
Please note that JavaScript cannot make a distinction between Option<T> and
Option<Option<T>>. This cannot be resolved using this type, as it suffers
from the same limitation. There is no way to distinguish between Null and
NonNull(Null). Nullable<Nullable<T>> does not provide additional
information.
§Examples
let maybe_10: Nullable<u8> = JsValue::new(10).try_js_into(context).unwrap();
assert_eq!(maybe_10, Nullable::NonNull(10u8));
let maybe_not: Nullable<u8> = JsValue::null().try_js_into(context).unwrap();
assert_eq!(maybe_not, Nullable::Null);let mut v: JsResult<Nullable<Option<u8>>> =
JsValue::undefined().try_js_into(context);
assert_eq!(v, Ok(Nullable::NonNull(None)));
v = JsValue::null().try_js_into(context);
assert_eq!(v, Ok(Nullable::Null));
v = JsValue::from(42).try_js_into(context);
assert_eq!(v, Ok(Nullable::NonNull(Some(42))));
assert_eq!(v.unwrap().flatten(), Some(42));Variants§
Implementations§
Source§impl<T> Nullable<T>
impl<T> Nullable<T>
Sourcepub const fn is_not_null(&self) -> bool
pub const fn is_not_null(&self) -> bool
Returns true if this value is Nullable::NotNull.
Sourcepub fn iter(&self) -> Iter<'_, T>
pub fn iter(&self) -> Iter<'_, T>
Returns an iterator over the possibly contained value.
§Examples
let x = Nullable::NonNull(4);
assert_eq!(x.iter().next(), Some(&4));
let x: Nullable<u32> = Nullable::Null;
assert_eq!(x.iter().next(), None);Sourcepub const fn as_ref(&self) -> Nullable<&T>
pub const fn as_ref(&self) -> Nullable<&T>
Converts from &Nullable<T> to Nullable<&T>.
§Examples
let text: Nullable<String> = Nullable::NonNull("Hello, world!".to_string());
// First, cast `Nullable<String>` to `Nullable<&String>` with `as_ref`,
// then consume *that* with `map`, leaving `text` on the stack.
let text_length: Nullable<usize> = text.as_ref().map(|s| s.len());
println!("still can print text: {text:?}");Sourcepub fn map<U, F>(self, f: F) -> Nullable<U>where
F: FnOnce(T) -> U,
pub fn map<U, F>(self, f: F) -> Nullable<U>where
F: FnOnce(T) -> U,
Maps a Nullable<T> to Nullable<U> by applying a function to a contained
value.
§Examples
let maybe_some_string = Nullable::NonNull(String::from("Hello, World!"));
// `Nullable::map` takes self *by value*, consuming `maybe_some_string`
let maybe_some_len = maybe_some_string.map(|s| s.len());
assert_eq!(maybe_some_len, Nullable::NonNull(13));
let x: Nullable<&str> = Nullable::Null;
assert_eq!(x.map(|s| s.len()), Nullable::Null);Sourcepub fn unwrap_or_default(self) -> Twhere
T: Default,
pub fn unwrap_or_default(self) -> Twhere
T: Default,
Returns the contained Nullable::NonNull value or a default.
Consumes the self argument then, if Nullable::NonNull, returns the contained
value, otherwise if Nullable::Null, returns the default value for that
type.
§Examples
let x: Nullable<u32> = Nullable::Null;
let y: Nullable<u32> = Nullable::NonNull(12);
assert_eq!(x.unwrap_or_default(), 0);
assert_eq!(y.unwrap_or_default(), 12);Trait Implementations§
Source§impl<'a, T> IntoIterator for &'a Nullable<T>
impl<'a, T> IntoIterator for &'a Nullable<T>
Source§impl<T> IntoIterator for Nullable<T>
impl<T> IntoIterator for Nullable<T>
Source§fn into_iter(self) -> IntoIter<T>
fn into_iter(self) -> IntoIter<T>
Returns a consuming iterator over the possibly contained value.
§Examples
let x = Nullable::NonNull("string");
let v: Vec<&str> = x.into_iter().collect();
assert_eq!(v, ["string"]);
let x = Nullable::Null;
let v: Vec<&str> = x.into_iter().collect();
assert!(v.is_empty());Source§impl<T> Ord for Nullable<T>where
T: Ord,
impl<T> Ord for Nullable<T>where
T: Ord,
1.21.0 · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
Source§impl<T> PartialOrd for Nullable<T>where
T: PartialOrd,
impl<T> PartialOrd for Nullable<T>where
T: PartialOrd,
impl<T> Copy for Nullable<T>where
T: Copy,
impl<T> Eq for Nullable<T>where
T: Eq,
impl<T> StructuralPartialEq for Nullable<T>
Auto Trait Implementations§
impl<T> Freeze for Nullable<T>where
T: Freeze,
impl<T> RefUnwindSafe for Nullable<T>where
T: RefUnwindSafe,
impl<T> Send for Nullable<T>where
T: Send,
impl<T> Sync for Nullable<T>where
T: Sync,
impl<T> Unpin for Nullable<T>where
T: Unpin,
impl<T> UnwindSafe for Nullable<T>where
T: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Comparable<K> for Q
impl<Q, K> Comparable<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoJsModule for T
impl<T> IntoJsModule for T
Source§fn into_js_module(self, context: &mut Context) -> Module
fn into_js_module(self, context: &mut Context) -> Module
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.