use std::{char, marker::PhantomData, rc::Rc, thread::JoinHandle};
use derive_more::with_trait::{Deref, Display, From, Into};
use serde::{Deserialize, Serialize};
use crate::{
GraphQLScalar, IntoFieldError, Scalar,
ast::{InputValue, Selection, ToInputValue},
executor::{ExecutionResult, Executor, Registry},
graphql_scalar,
macros::reflect,
parser::{LexerError, ParseError, ScalarToken, Token},
schema::meta::MetaType,
types::{
async_await::GraphQLValueAsync,
base::{GraphQLType, GraphQLValue},
subscriptions::GraphQLSubscriptionValue,
},
value::{
FromScalarValue, ParseScalarResult, ScalarValue, ToScalarValue, TryToPrimitive, Value,
WrongInputScalarTypeError,
},
};
#[derive(
Clone, Debug, Deref, Deserialize, Display, Eq, From, GraphQLScalar, Into, PartialEq, Serialize,
)]
#[deref(forward)]
#[from(Box<str>, String)]
#[into(Box<str>, String)]
#[graphql(parse_token(String, i32))]
pub struct ID(Box<str>);
impl ID {
fn to_output(&self) -> &str {
&self.0
}
fn from_input<S: ScalarValue>(v: &Scalar<S>) -> Result<Self, WrongInputScalarTypeError<'_, S>> {
v.try_to_string()
.or_else(|| v.try_to_int().as_ref().map(ToString::to_string))
.map(|s| Self(s.into()))
.ok_or_else(|| WrongInputScalarTypeError {
type_name: arcstr::literal!("String` or `Int"),
input: &**v,
})
}
}
impl ID {
#[must_use]
pub fn new<S: Into<String>>(value: S) -> Self {
ID(value.into().into())
}
}
#[graphql_scalar]
#[graphql(
with = impl_string_scalar,
to_output_with = String::as_str
from_input_with = __builtin,
)]
type String = std::string::String;
mod impl_string_scalar {
use super::*;
impl<'s, S> FromScalarValue<'s, S> for String
where
S: TryToPrimitive<'s, Self, Error: IntoFieldError<S>> + 's,
{
type Error = S::Error;
fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
v.try_to_primitive()
}
}
pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
if let ScalarToken::String(value) = value {
let mut ret = String::with_capacity(value.len());
let mut char_iter = value.chars();
while let Some(ch) = char_iter.next() {
match ch {
'\\' => match char_iter.next() {
Some('"') => {
ret.push('"');
}
Some('/') => {
ret.push('/');
}
Some('n') => {
ret.push('\n');
}
Some('r') => {
ret.push('\r');
}
Some('t') => {
ret.push('\t');
}
Some('\\') => {
ret.push('\\');
}
Some('f') => {
ret.push('\u{000c}');
}
Some('b') => {
ret.push('\u{0008}');
}
Some('u') => {
ret.push(parse_unicode_codepoint(&mut char_iter)?);
}
Some(s) => {
return Err(ParseError::LexerError(LexerError::UnknownEscapeSequence(
format!("\\{s}"),
)));
}
None => return Err(ParseError::LexerError(LexerError::UnterminatedString)),
},
ch => {
ret.push(ch);
}
}
}
Ok(ret.into())
} else {
Err(ParseError::unexpected_token(Token::Scalar(value)))
}
}
}
fn parse_unicode_codepoint<I>(char_iter: &mut I) -> Result<char, ParseError>
where
I: Iterator<Item = char>,
{
let escaped_code_point = char_iter
.next()
.ok_or_else(|| {
ParseError::LexerError(LexerError::UnknownEscapeSequence(String::from("\\u")))
})
.and_then(|c1| {
char_iter
.next()
.map(|c2| format!("{c1}{c2}"))
.ok_or_else(|| {
ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\u{c1}")))
})
})
.and_then(|mut s| {
char_iter
.next()
.ok_or_else(|| {
ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\u{s}")))
})
.map(|c2| {
s.push(c2);
s
})
})
.and_then(|mut s| {
char_iter
.next()
.ok_or_else(|| {
ParseError::LexerError(LexerError::UnknownEscapeSequence(format!("\\u{s}")))
})
.map(|c2| {
s.push(c2);
s
})
})?;
let code_point = u32::from_str_radix(&escaped_code_point, 16).map_err(|_| {
ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
"\\u{escaped_code_point}",
)))
})?;
char::from_u32(code_point).ok_or_else(|| {
ParseError::LexerError(LexerError::UnknownEscapeSequence(format!(
"\\u{escaped_code_point}",
)))
})
}
#[graphql_scalar]
#[graphql(
name = "String",
with = impl_arcstr_scalar,
to_output_with = ScalarValue::from_displayable,
parse_token(String)
)]
type ArcStr = arcstr::ArcStr;
mod impl_arcstr_scalar {
use super::ArcStr;
use crate::{FromScalarValue, Scalar, ScalarValue};
pub(super) fn from_input<S: ScalarValue>(
v: &Scalar<S>,
) -> Result<ArcStr, <&str as FromScalarValue<'_, S>>::Error> {
if let Some(s) = v.downcast_type::<ArcStr>() {
Ok(s.clone())
} else {
v.try_to::<&str>().map(ArcStr::from)
}
}
}
#[graphql_scalar]
#[graphql(
name = "String",
with = impl_compactstring_scalar,
to_output_with = ScalarValue::from_displayable,
parse_token(String),
)]
type CompactString = compact_str::CompactString;
mod impl_compactstring_scalar {
use super::CompactString;
use crate::{FromScalarValue, Scalar, ScalarValue};
pub(super) fn from_input<S: ScalarValue>(
v: &Scalar<S>,
) -> Result<CompactString, <&str as FromScalarValue<'_, S>>::Error> {
if let Some(s) = v.downcast_type::<CompactString>() {
Ok(s.clone())
} else {
v.try_to::<&str>().map(CompactString::from)
}
}
}
impl<S> reflect::WrappedType<S> for str {
const VALUE: reflect::WrappedValue = 1;
}
impl<S> reflect::BaseType<S> for str {
const NAME: reflect::Type = "String";
}
impl<S> reflect::BaseSubTypes<S> for str {
const NAMES: reflect::Types = &[<Self as reflect::BaseType<S>>::NAME];
}
impl<S> GraphQLType<S> for str
where
S: ScalarValue,
{
fn name(_: &()) -> Option<ArcStr> {
Some(arcstr::literal!("String"))
}
fn meta(_: &(), registry: &mut Registry<S>) -> MetaType<S> {
registry.build_scalar_type::<String>(&()).into_meta()
}
}
impl<S> GraphQLValue<S> for str
where
S: ScalarValue,
{
type Context = ();
type TypeInfo = ();
fn type_name(&self, info: &Self::TypeInfo) -> Option<ArcStr> {
<Self as GraphQLType<S>>::name(info)
}
fn resolve(
&self,
_: &(),
_: Option<&[Selection<S>]>,
_: &Executor<Self::Context, S>,
) -> ExecutionResult<S> {
Ok(Value::Scalar(self.to_scalar_value()))
}
}
impl<S> GraphQLValueAsync<S> for str
where
S: ScalarValue + Send + Sync,
{
fn resolve_async<'a>(
&'a self,
info: &'a Self::TypeInfo,
selection_set: Option<&'a [Selection<S>]>,
executor: &'a Executor<Self::Context, S>,
) -> crate::BoxFuture<'a, ExecutionResult<S>> {
use futures::future;
Box::pin(future::ready(self.resolve(info, selection_set, executor)))
}
}
impl<'s, S> FromScalarValue<'s, S> for &'s str
where
S: TryToPrimitive<'s, Self, Error: IntoFieldError<S>> + 's,
{
type Error = S::Error;
fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
v.try_to_primitive()
}
}
impl<S: ScalarValue> ToScalarValue<S> for str {
fn to_scalar_value(&self) -> S {
S::from_displayable(self)
}
}
impl<S> ToInputValue<S> for str
where
Self: ToScalarValue<S>,
{
fn to_input_value(&self) -> InputValue<S> {
InputValue::Scalar(self.to_scalar_value())
}
}
#[graphql_scalar]
#[graphql(with = impl_boolean_scalar, from_input_with = __builtin)]
type Boolean = bool;
mod impl_boolean_scalar {
use super::*;
impl<'s, S> FromScalarValue<'s, S> for Boolean
where
S: TryToPrimitive<'s, Self, Error: IntoFieldError<S>> + 's,
{
type Error = S::Error;
fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
v.try_to_primitive()
}
}
pub(super) fn to_output<S: ScalarValue>(v: &Boolean) -> S {
(*v).into()
}
pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
Err(ParseError::unexpected_token(Token::Scalar(value)))
}
}
#[graphql_scalar]
#[graphql(with = impl_int_scalar, from_input_with = __builtin)]
type Int = i32;
mod impl_int_scalar {
use super::*;
impl<'s, S> FromScalarValue<'s, S> for Int
where
S: TryToPrimitive<'s, Self, Error: IntoFieldError<S>> + 's,
{
type Error = S::Error;
fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
v.try_to_primitive()
}
}
pub(super) fn to_output<S: ScalarValue>(v: &Int) -> S {
(*v).into()
}
pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
if let ScalarToken::Int(v) = value {
v.parse()
.map_err(|_| ParseError::unexpected_token(Token::Scalar(value)))
.map(|s: i32| s.into())
} else {
Err(ParseError::unexpected_token(Token::Scalar(value)))
}
}
}
#[graphql_scalar]
#[graphql(with = impl_float_scalar, from_input_with = __builtin)]
type Float = f64;
mod impl_float_scalar {
use super::*;
impl<'s, S> FromScalarValue<'s, S> for Float
where
S: TryToPrimitive<'s, Self, Error: IntoFieldError<S>> + 's,
{
type Error = S::Error;
fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
v.try_to_primitive()
}
}
pub(super) fn to_output<S: ScalarValue>(v: &Float) -> S {
(*v).into()
}
pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
match value {
ScalarToken::Int(v) => v
.parse()
.map_err(|_| ParseError::unexpected_token(Token::Scalar(value)))
.map(|s: i32| f64::from(s).into()),
ScalarToken::Float(v) => v
.parse()
.map_err(|_| ParseError::unexpected_token(Token::Scalar(value)))
.map(|s: f64| s.into()),
ScalarToken::String(_) => Err(ParseError::unexpected_token(Token::Scalar(value))),
}
}
}
#[derive(Debug)]
pub struct EmptyMutation<T: ?Sized = ()>(PhantomData<JoinHandle<Box<T>>>);
crate::sa::assert_impl_all!(EmptyMutation<Rc<String>>: Send, Sync);
impl<T: ?Sized> EmptyMutation<T> {
#[inline]
pub fn new() -> Self {
Self(PhantomData)
}
}
impl<S, T> GraphQLType<S> for EmptyMutation<T>
where
S: ScalarValue,
{
fn name(_: &()) -> Option<ArcStr> {
Some(arcstr::literal!("_EmptyMutation"))
}
fn meta(_: &(), registry: &mut Registry<S>) -> MetaType<S> {
registry.build_object_type::<Self>(&(), &[]).into_meta()
}
}
impl<S, T> GraphQLValue<S> for EmptyMutation<T>
where
S: ScalarValue,
{
type Context = T;
type TypeInfo = ();
fn type_name(&self, info: &Self::TypeInfo) -> Option<ArcStr> {
<Self as GraphQLType<S>>::name(info)
}
}
impl<S, T> GraphQLValueAsync<S> for EmptyMutation<T>
where
Self::TypeInfo: Sync,
Self::Context: Sync,
S: ScalarValue + Send + Sync,
{
}
impl<T> Default for EmptyMutation<T> {
fn default() -> Self {
Self::new()
}
}
pub struct EmptySubscription<T: ?Sized = ()>(PhantomData<JoinHandle<Box<T>>>);
crate::sa::assert_impl_all!(EmptySubscription<Rc<String>>: Send, Sync);
impl<T: ?Sized> EmptySubscription<T> {
#[inline]
pub fn new() -> Self {
Self(PhantomData)
}
}
impl<S, T> GraphQLType<S> for EmptySubscription<T>
where
S: ScalarValue,
{
fn name(_: &()) -> Option<ArcStr> {
Some(arcstr::literal!("_EmptySubscription"))
}
fn meta(_: &(), registry: &mut Registry<S>) -> MetaType<S> {
registry.build_object_type::<Self>(&(), &[]).into_meta()
}
}
impl<S, T> GraphQLValue<S> for EmptySubscription<T>
where
S: ScalarValue,
{
type Context = T;
type TypeInfo = ();
fn type_name(&self, info: &Self::TypeInfo) -> Option<ArcStr> {
<Self as GraphQLType<S>>::name(info)
}
}
impl<T, S> GraphQLSubscriptionValue<S> for EmptySubscription<T>
where
Self::TypeInfo: Sync,
Self::Context: Sync,
S: ScalarValue + Send + Sync + 'static,
{
}
impl<T> Default for EmptySubscription<T> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use crate::{
parser::ScalarToken,
value::{DefaultScalarValue, ParseScalarValue, ScalarValue as _},
};
use super::{EmptyMutation, EmptySubscription, ID};
#[test]
fn test_id_from_string() {
let actual = ID::from(String::from("foo"));
let expected = ID("foo".into());
assert_eq!(actual, expected);
}
#[test]
fn test_id_new() {
let actual = ID::new("foo");
let expected = ID("foo".into());
assert_eq!(actual, expected);
}
#[test]
fn test_id_deref() {
let id = ID("foo".into());
assert_eq!(id.len(), 3);
}
#[test]
fn test_id_display() {
let id = ID("foo".into());
assert_eq!(id.to_string(), "foo");
}
#[test]
fn parse_strings() {
fn parse_string(s: &str, expected: &str) {
let s =
<String as ParseScalarValue<DefaultScalarValue>>::from_str(ScalarToken::String(s));
assert!(s.is_ok(), "A parsing error occurred: {s:?}");
let s: Option<String> = s.unwrap().try_to().ok();
assert!(s.is_some(), "No string returned");
assert_eq!(s.unwrap(), expected);
}
parse_string("simple", "simple");
parse_string(" white space ", " white space ");
parse_string(r#"quote \""#, "quote \"");
parse_string(r"escaped \n\r\b\t\f", "escaped \n\r\u{0008}\t\u{000c}");
parse_string(r"slashes \\ \/", "slashes \\ /");
parse_string(
r"unicode \u1234\u5678\u90AB\uCDEF",
"unicode \u{1234}\u{5678}\u{90ab}\u{cdef}",
);
}
#[test]
fn parse_f64_from_int() {
for (v, expected) in [
("0", 0),
("128", 128),
("1601942400", 1601942400),
("1696550400", 1696550400),
("-1", -1),
] {
let n = <f64 as ParseScalarValue<DefaultScalarValue>>::from_str(ScalarToken::Int(v));
assert!(n.is_ok(), "A parsing error occurred: {:?}", n.unwrap_err());
let n: Option<f64> = n.unwrap().try_to().ok();
assert!(n.is_some(), "No `f64` returned");
assert_eq!(n.unwrap(), f64::from(expected));
}
}
#[test]
fn parse_f64_from_float() {
for (v, expected) in [
("0.", 0.),
("1.2", 1.2),
("1601942400.", 1601942400.),
("1696550400.", 1696550400.),
("-1.2", -1.2),
] {
let n = <f64 as ParseScalarValue<DefaultScalarValue>>::from_str(ScalarToken::Float(v));
assert!(n.is_ok(), "A parsing error occurred: {:?}", n.unwrap_err());
let n: Option<f64> = n.unwrap().try_to().ok();
assert!(n.is_some(), "No `f64` returned");
assert_eq!(n.unwrap(), expected);
}
}
#[test]
fn empty_mutation_is_send() {
fn check_if_send<T: Send>() {}
check_if_send::<EmptyMutation<()>>();
}
#[test]
fn empty_subscription_is_send() {
fn check_if_send<T: Send>() {}
check_if_send::<EmptySubscription<()>>();
}
#[test]
fn default_is_invariant_over_type() {
struct Bar;
let _ = EmptySubscription::<Bar>::default();
let _ = EmptyMutation::<Bar>::default();
}
}