use crate::{
ast::{FromInputValue, InputValue, Selection, ToInputValue},
executor::{ExecutionResult, Executor, Registry},
schema::meta::MetaType,
types::{
async_await::GraphQLValueAsync,
base::{GraphQLType, GraphQLValue},
marker::IsInputType,
},
value::{ScalarValue, Value},
};
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Nullable<T> {
ImplicitNull,
ExplicitNull,
Some(T),
}
impl<T> Default for Nullable<T> {
fn default() -> Self {
Self::ImplicitNull
}
}
impl<T> Nullable<T> {
#[inline]
pub fn is_explicit_null(&self) -> bool {
match self {
Self::ExplicitNull => true,
_ => false,
}
}
#[inline]
pub fn is_implicit_null(&self) -> bool {
match self {
Self::ImplicitNull => true,
_ => false,
}
}
#[inline]
pub fn is_some(&self) -> bool {
match self {
Self::Some(_) => true,
_ => false,
}
}
#[inline]
pub fn is_null(&self) -> bool {
match self {
Self::Some(_) => false,
_ => true,
}
}
#[inline]
pub fn as_mut(&mut self) -> Nullable<&mut T> {
match *self {
Self::Some(ref mut x) => Nullable::Some(x),
Self::ImplicitNull => Nullable::ImplicitNull,
Self::ExplicitNull => Nullable::ExplicitNull,
}
}
#[inline]
#[track_caller]
pub fn expect(self, msg: &str) -> T {
self.some().expect(msg)
}
#[inline]
pub fn unwrap_or(self, default: T) -> T {
self.some().unwrap_or(default)
}
#[inline]
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
self.some().unwrap_or_else(f)
}
#[inline]
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
match self {
Self::Some(x) => Nullable::Some(f(x)),
Self::ImplicitNull => Nullable::ImplicitNull,
Self::ExplicitNull => Nullable::ExplicitNull,
}
}
#[inline]
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
self.some().map_or(default, f)
}
#[inline]
pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
self.some().map_or_else(default, f)
}
#[inline]
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
self.some().ok_or(err)
}
#[inline]
pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
self.some().ok_or_else(err)
}
#[inline]
pub fn or(self, b: Self) -> Self {
match self {
Self::Some(_) => self,
_ => b,
}
}
#[inline]
pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
match self {
Self::Some(_) => self,
_ => f(),
}
}
#[inline]
pub fn replace(&mut self, value: T) -> Self {
std::mem::replace(self, Self::Some(value))
}
pub fn some(self) -> Option<T> {
match self {
Self::Some(v) => Some(v),
_ => None,
}
}
pub fn explicit(self) -> Option<Option<T>> {
match self {
Self::Some(v) => Some(Some(v)),
Self::ExplicitNull => Some(None),
Self::ImplicitNull => None,
}
}
}
impl<T: Copy> Nullable<&T> {
pub fn copied(self) -> Nullable<T> {
self.map(|&t| t)
}
}
impl<T: Copy> Nullable<&mut T> {
pub fn copied(self) -> Nullable<T> {
self.map(|&mut t| t)
}
}
impl<T: Clone> Nullable<&T> {
pub fn cloned(self) -> Nullable<T> {
self.map(|t| t.clone())
}
}
impl<T: Clone> Nullable<&mut T> {
pub fn cloned(self) -> Nullable<T> {
self.map(|t| t.clone())
}
}
impl<S, T> GraphQLType<S> for Nullable<T>
where
T: GraphQLType<S>,
S: ScalarValue,
{
fn name(_: &Self::TypeInfo) -> Option<&'static str> {
None
}
fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where
S: 'r,
{
registry.build_nullable_type::<T>(info).into_meta()
}
}
impl<S, T> GraphQLValue<S> for Nullable<T>
where
S: ScalarValue,
T: GraphQLValue<S>,
{
type Context = T::Context;
type TypeInfo = T::TypeInfo;
fn type_name(&self, _: &Self::TypeInfo) -> Option<&'static str> {
None
}
fn resolve(
&self,
info: &Self::TypeInfo,
_: Option<&[Selection<S>]>,
executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> {
match *self {
Self::Some(ref obj) => executor.resolve(info, obj),
_ => Ok(Value::null()),
}
}
}
impl<S, T> GraphQLValueAsync<S> for Nullable<T>
where
T: GraphQLValueAsync<S>,
T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync,
{
fn resolve_async<'a>(
&'a self,
info: &'a Self::TypeInfo,
_: Option<&'a [Selection<S>]>,
executor: &'a Executor<Self::Context, S>,
) -> crate::BoxFuture<'a, ExecutionResult<S>> {
let f = async move {
let value = match self {
Self::Some(obj) => executor.resolve_into_value_async(info, obj).await,
_ => Value::null(),
};
Ok(value)
};
Box::pin(f)
}
}
impl<S, T> FromInputValue<S> for Nullable<T>
where
T: FromInputValue<S>,
S: ScalarValue,
{
fn from_input_value(v: &InputValue<S>) -> Option<Nullable<T>> {
match v {
&InputValue::Null => Some(Self::ExplicitNull),
v => v.convert().map(Self::Some),
}
}
fn from_implicit_null() -> Self {
Self::ImplicitNull
}
}
impl<S, T> ToInputValue<S> for Nullable<T>
where
T: ToInputValue<S>,
S: ScalarValue,
{
fn to_input_value(&self) -> InputValue<S> {
match *self {
Self::Some(ref v) => v.to_input_value(),
_ => InputValue::null(),
}
}
}
impl<S, T> IsInputType<S> for Nullable<T>
where
T: IsInputType<S>,
S: ScalarValue,
{
}