use std::fmt;
use serde::{de, ser::Serialize};
use crate::{
parser::{ParseError, ScalarToken},
GraphQLScalarValue,
};
pub type ParseScalarResult<'a, S = DefaultScalarValue> = Result<S, ParseError<'a>>;
pub trait ParseScalarValue<S = DefaultScalarValue> {
fn from_str(value: ScalarToken<'_>) -> ParseScalarResult<'_, S>;
}
pub trait ScalarValue:
fmt::Debug
+ fmt::Display
+ PartialEq
+ Clone
+ Serialize
+ From<String>
+ From<bool>
+ From<i32>
+ From<f64>
+ 'static
{
type Visitor: for<'de> de::Visitor<'de, Value = Self> + Default;
fn is_type<'a, T>(&'a self) -> bool
where
T: 'a,
&'a Self: Into<Option<&'a T>>,
{
self.into().is_some()
}
fn as_int(&self) -> Option<i32>;
fn as_string(&self) -> Option<String>;
fn into_string(self) -> Option<String>;
fn as_str(&self) -> Option<&str>;
fn as_float(&self) -> Option<f64>;
fn as_boolean(&self) -> Option<bool>;
fn into_another<S: ScalarValue>(self) -> S {
if let Some(i) = self.as_int() {
S::from(i)
} else if let Some(f) = self.as_float() {
S::from(f)
} else if let Some(b) = self.as_boolean() {
S::from(b)
} else if let Some(s) = self.into_string() {
S::from(s)
} else {
unreachable!("`ScalarValue` must represent at least one of the GraphQL spec types")
}
}
}
#[derive(Debug, PartialEq, Clone, GraphQLScalarValue)]
#[allow(missing_docs)]
pub enum DefaultScalarValue {
Int(i32),
Float(f64),
String(String),
Boolean(bool),
}
impl ScalarValue for DefaultScalarValue {
type Visitor = DefaultScalarValueVisitor;
fn as_int(&self) -> Option<i32> {
match *self {
Self::Int(ref i) => Some(*i),
_ => None,
}
}
fn as_float(&self) -> Option<f64> {
match *self {
Self::Int(ref i) => Some(*i as f64),
Self::Float(ref f) => Some(*f),
_ => None,
}
}
fn as_str(&self) -> Option<&str> {
match *self {
Self::String(ref s) => Some(s.as_str()),
_ => None,
}
}
fn as_string(&self) -> Option<String> {
match *self {
Self::String(ref s) => Some(s.clone()),
_ => None,
}
}
fn into_string(self) -> Option<String> {
match self {
Self::String(s) => Some(s),
_ => None,
}
}
fn as_boolean(&self) -> Option<bool> {
match *self {
Self::Boolean(ref b) => Some(*b),
_ => None,
}
}
fn into_another<S: ScalarValue>(self) -> S {
match self {
Self::Int(i) => S::from(i),
Self::Float(f) => S::from(f),
Self::String(s) => S::from(s),
Self::Boolean(b) => S::from(b),
}
}
}
impl<'a> From<&'a str> for DefaultScalarValue {
fn from(s: &'a str) -> Self {
Self::String(s.into())
}
}
#[derive(Default, Clone, Copy, Debug)]
pub struct DefaultScalarValueVisitor;
impl<'de> de::Visitor<'de> for DefaultScalarValueVisitor {
type Value = DefaultScalarValue;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid input value")
}
fn visit_bool<E>(self, value: bool) -> Result<DefaultScalarValue, E> {
Ok(DefaultScalarValue::Boolean(value))
}
fn visit_i64<E>(self, value: i64) -> Result<DefaultScalarValue, E>
where
E: de::Error,
{
if value >= i64::from(i32::min_value()) && value <= i64::from(i32::max_value()) {
Ok(DefaultScalarValue::Int(value as i32))
} else {
Ok(DefaultScalarValue::Float(value as f64))
}
}
fn visit_u64<E>(self, value: u64) -> Result<DefaultScalarValue, E>
where
E: de::Error,
{
if value <= i32::max_value() as u64 {
self.visit_i64(value as i64)
} else {
Ok(DefaultScalarValue::Float(value as f64))
}
}
fn visit_f64<E>(self, value: f64) -> Result<DefaultScalarValue, E> {
Ok(DefaultScalarValue::Float(value))
}
fn visit_str<E>(self, value: &str) -> Result<DefaultScalarValue, E>
where
E: de::Error,
{
self.visit_string(value.into())
}
fn visit_string<E>(self, value: String) -> Result<DefaultScalarValue, E> {
Ok(DefaultScalarValue::String(value))
}
}