use std::{char, fmt, marker::PhantomData, ops::Deref, rc::Rc, thread::JoinHandle, u32};
use serde::{Deserialize, Serialize};
use crate::{
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::{ParseScalarResult, ScalarValue, Value},
GraphQLScalar,
};
#[derive(Clone, Debug, Deserialize, Eq, GraphQLScalar, PartialEq, Serialize)]
#[graphql(parse_token(String, i32))]
pub struct ID(String);
impl ID {
fn to_output<S: ScalarValue>(&self) -> Value<S> {
Value::scalar(self.0.clone())
}
fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Self, String> {
v.as_string_value()
.map(str::to_owned)
.or_else(|| v.as_int_value().as_ref().map(ToString::to_string))
.map(Self)
.ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
}
}
impl From<String> for ID {
fn from(s: String) -> ID {
ID(s)
}
}
impl ID {
pub fn new<S: Into<String>>(value: S) -> Self {
ID(value.into())
}
}
impl Deref for ID {
type Target = str;
fn deref(&self) -> &str {
&self.0
}
}
impl fmt::Display for ID {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[graphql_scalar(with = impl_string_scalar)]
type String = std::string::String;
mod impl_string_scalar {
use super::*;
pub(super) fn to_output<S: ScalarValue>(v: &str) -> Value<S> {
Value::scalar(v.to_owned())
}
pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<String, String> {
v.as_string_value()
.map(str::to_owned)
.ok_or_else(|| format!("Expected `String`, found: {v}"))
}
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}",
)))
})
}
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<&'static str> {
Some("String")
}
fn meta<'r>(_: &(), registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where
S: 'r,
{
registry.build_scalar_type::<String>(&()).into_meta()
}
}
impl<S> GraphQLValue<S> for str
where
S: ScalarValue,
{
type Context = ();
type TypeInfo = ();
fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
<Self as GraphQLType<S>>::name(info)
}
fn resolve(
&self,
_: &(),
_: Option<&[Selection<S>]>,
_: &Executor<Self::Context, S>,
) -> ExecutionResult<S> {
Ok(Value::scalar(String::from(self)))
}
}
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, crate::ExecutionResult<S>> {
use futures::future;
Box::pin(future::ready(self.resolve(info, selection_set, executor)))
}
}
impl<'a, S> ToInputValue<S> for &'a str
where
S: ScalarValue,
{
fn to_input_value(&self) -> InputValue<S> {
InputValue::scalar(String::from(*self))
}
}
#[graphql_scalar(with = impl_boolean_scalar)]
type Boolean = bool;
mod impl_boolean_scalar {
use super::*;
pub(super) fn to_output<S: ScalarValue>(v: &Boolean) -> Value<S> {
Value::scalar(*v)
}
pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Boolean, String> {
v.as_scalar_value()
.and_then(ScalarValue::as_bool)
.ok_or_else(|| format!("Expected `Boolean`, found: {v}"))
}
pub(super) fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
Err(ParseError::unexpected_token(Token::Scalar(value)))
}
}
#[graphql_scalar(with = impl_int_scalar)]
type Int = i32;
mod impl_int_scalar {
use super::*;
pub(super) fn to_output<S: ScalarValue>(v: &Int) -> Value<S> {
Value::scalar(*v)
}
pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Int, String> {
v.as_int_value()
.ok_or_else(|| format!("Expected `Int`, found: {v}"))
}
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(with = impl_float_scalar)]
type Float = f64;
mod impl_float_scalar {
use super::*;
pub(super) fn to_output<S: ScalarValue>(v: &Float) -> Value<S> {
Value::scalar(*v)
}
pub(super) fn from_input<S: ScalarValue>(v: &InputValue<S>) -> Result<Float, String> {
v.as_float_value()
.ok_or_else(|| format!("Expected `Float`, found: {v}"))
}
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<&'static str> {
Some("_EmptyMutation")
}
fn meta<'r>(_: &(), registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where
S: 'r,
{
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<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
<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<&'static str> {
Some("_EmptySubscription")
}
fn meta<'r>(_: &(), registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where
S: 'r,
{
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<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
<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},
};
use super::{EmptyMutation, EmptySubscription, ID};
#[test]
fn test_id_from_string() {
let actual = ID::from(String::from("foo"));
let expected = ID(String::from("foo"));
assert_eq!(actual, expected);
}
#[test]
fn test_id_new() {
let actual = ID::new("foo");
let expected = ID(String::from("foo"));
assert_eq!(actual, expected);
}
#[test]
fn test_id_deref() {
let id = ID(String::from("foo"));
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().into();
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().into();
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().into();
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();
}
}