Add `parse_value` and `from_value` funcntions.

This commit is contained in:
Sunli 2020-10-11 20:24:31 +08:00
parent 935cedc057
commit e056edbaa0
39 changed files with 1692 additions and 556 deletions

View File

@ -15,6 +15,9 @@ jobs:
max-parallel: 1
matrix:
package:
- name: async-graphql-value
registryName: async-graphql-value
path: value
- name: async-graphql-parser
registryName: async-graphql-parser
path: parser

View File

@ -25,6 +25,7 @@ nightly = []
[dependencies]
async-graphql-derive = { path = "derive", version = "2.0.0-alpha.24" }
async-graphql-value = { path = "value", version = "2.0.0-alpha.24" }
async-graphql-parser = { path = "parser", version = "2.0.0-alpha.24" }
async-stream = "0.3"
@ -66,6 +67,7 @@ features = ["nightly"]
[workspace]
members = [
"value",
"parser",
"derive",
"integrations/actix-web",

View File

@ -125,7 +125,7 @@ pub fn generate(object_args: &args::InputObject) -> GeneratorResult<TokenStream>
put_fields.push(quote! {
map.insert(
#crate_name::parser::types::Name::new(#name),
#crate_name::Name::new(#name),
#crate_name::InputValueType::to_value(&self.#ident)
);
});

View File

@ -13,6 +13,7 @@ keywords = ["futures", "async", "graphql"]
categories = ["network-programming", "asynchronous"]
[dependencies]
async-graphql-value = { path = "../value", version = "2.0.0-alpha.24" }
pest = "2.1.3"
pest_derive = "2.1.0"
serde_json = "1.0.57"

View File

@ -5,7 +5,8 @@
//! it into Rust types.
#![forbid(unsafe_code)]
use crate::types::{Name, OperationType};
use crate::types::OperationType;
use async_graphql_value::Name;
use pest::error::LineColLocation;
use pest::RuleType;
use serde::{Serialize, Serializer};

View File

@ -1,4 +1,5 @@
use super::*;
use async_graphql_value::Name;
/// Parse a GraphQL query document.
///

View File

@ -15,6 +15,7 @@ mod executable;
mod service;
mod utils;
use async_graphql_value::{ConstValue, Name, Number, Value};
pub use executable::parse_query;
pub use service::parse_schema;

View File

@ -1,6 +1,7 @@
//! Executable document-related GraphQL types.
use super::*;
use async_graphql_value::{ConstValue, Name, Value};
/// An executable GraphQL file or request string.
///

View File

@ -6,25 +6,17 @@
//!
//! This follows the [June 2018 edition of the GraphQL spec](https://spec.graphql.org/June2018/).
use crate::pos::Positioned;
use serde::de::Deserializer;
use serde::ser::{Error as _, Serializer};
use serde::{Deserialize, Serialize};
use std::borrow::{Borrow, Cow};
use std::collections::{hash_map, BTreeMap, HashMap};
use std::convert::{TryFrom, TryInto};
use std::fmt::{self, Display, Formatter, Write};
use std::ops::Deref;
pub use executable::*;
pub use serde_json::Number;
pub use service::*;
use std::iter::FromIterator;
use std::sync::Arc;
mod executable;
mod service;
use crate::pos::Positioned;
use async_graphql_value::{ConstValue, Name, Value};
use std::collections::{hash_map, HashMap};
use std::fmt::{self, Display, Formatter, Write};
pub use executable::*;
pub use service::*;
/// The type of an operation; `query`, `mutation` or `subscription`.
///
/// [Reference](https://spec.graphql.org/June2018/#OperationType).
@ -109,399 +101,6 @@ impl Display for BaseType {
}
}
/// A resolved GraphQL value, for example `1` or `"Hello World!"`.
///
/// It can be serialized and deserialized. Enums will be converted to strings. Attempting to
/// serialize `Upload` will fail, and `Enum` and `Upload` cannot be deserialized.
///
/// [Reference](https://spec.graphql.org/June2018/#Value).
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ConstValue {
/// `null`.
Null,
/// A number.
Number(Number),
/// A string.
String(String),
/// A boolean.
Boolean(bool),
/// An enum. These are typically in `SCREAMING_SNAKE_CASE`.
#[serde(skip_deserializing)]
Enum(Name),
/// A list of values.
List(Vec<ConstValue>),
/// An object. This is a map of keys to values.
Object(BTreeMap<Name, ConstValue>),
}
impl From<()> for ConstValue {
fn from((): ()) -> Self {
ConstValue::Null
}
}
macro_rules! from_integer {
($($ty:ident),*) => {
$(
impl From<$ty> for ConstValue {
fn from(n: $ty) -> Self {
ConstValue::Number(n.into())
}
}
)*
};
}
from_integer!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
impl From<f32> for ConstValue {
fn from(f: f32) -> Self {
From::from(f as f64)
}
}
impl From<f64> for ConstValue {
fn from(f: f64) -> Self {
Number::from_f64(f).map_or(ConstValue::Null, ConstValue::Number)
}
}
impl From<bool> for ConstValue {
fn from(value: bool) -> Self {
ConstValue::Boolean(value)
}
}
impl From<String> for ConstValue {
fn from(value: String) -> Self {
ConstValue::String(value)
}
}
impl<'a> From<&'a str> for ConstValue {
fn from(value: &'a str) -> Self {
ConstValue::String(value.into())
}
}
impl<'a> From<Cow<'a, str>> for ConstValue {
fn from(f: Cow<'a, str>) -> Self {
ConstValue::String(f.into_owned())
}
}
impl<T: Into<ConstValue>> FromIterator<T> for ConstValue {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
ConstValue::List(iter.into_iter().map(Into::into).collect())
}
}
impl<'a, T: Clone + Into<ConstValue>> From<&'a [T]> for ConstValue {
fn from(f: &'a [T]) -> Self {
ConstValue::List(f.iter().cloned().map(Into::into).collect())
}
}
impl<T: Into<ConstValue>> From<Vec<T>> for ConstValue {
fn from(f: Vec<T>) -> Self {
ConstValue::List(f.into_iter().map(Into::into).collect())
}
}
impl From<BTreeMap<Name, ConstValue>> for ConstValue {
fn from(f: BTreeMap<Name, ConstValue>) -> Self {
ConstValue::Object(f)
}
}
impl PartialEq<serde_json::Value> for ConstValue {
fn eq(&self, other: &serde_json::Value) -> bool {
match (self, other) {
(ConstValue::Null, serde_json::Value::Null) => true,
(ConstValue::Number(a), serde_json::Value::Number(b)) => a == b,
(ConstValue::String(a), serde_json::Value::String(b)) => a == b,
(ConstValue::Boolean(a), serde_json::Value::Bool(b)) => a == b,
(ConstValue::Enum(a), serde_json::Value::String(b)) => a == b,
(ConstValue::List(a), serde_json::Value::Array(b)) => {
if a.len() != b.len() {
return false;
}
a.iter().zip(b.iter()).all(|(a, b)| a == b)
}
(ConstValue::Object(a), serde_json::Value::Object(b)) => {
if a.len() != b.len() {
return false;
}
for (a_key, a_value) in a.iter() {
if let Some(b_value) = b.get(a_key.as_str()) {
if b_value != a_value {
return false;
}
} else {
return false;
}
}
true
}
_ => false,
}
}
}
impl PartialEq<ConstValue> for serde_json::Value {
fn eq(&self, other: &ConstValue) -> bool {
other == self
}
}
impl ConstValue {
/// Convert this `ConstValue` into a `Value`.
#[must_use]
pub fn into_value(self) -> Value {
match self {
Self::Null => Value::Null,
Self::Number(num) => Value::Number(num),
Self::String(s) => Value::String(s),
Self::Boolean(b) => Value::Boolean(b),
Self::Enum(v) => Value::Enum(v),
Self::List(items) => {
Value::List(items.into_iter().map(ConstValue::into_value).collect())
}
Self::Object(map) => Value::Object(
map.into_iter()
.map(|(key, value)| (key, value.into_value()))
.collect(),
),
}
}
/// Attempt to convert the value into JSON. This is equivalent to the `TryFrom` implementation.
///
/// # Errors
///
/// Fails if serialization fails (see enum docs for more info).
pub fn into_json(self) -> serde_json::Result<serde_json::Value> {
self.try_into()
}
/// Attempt to convert JSON into a value. This is equivalent to the `TryFrom` implementation.
///
/// # Errors
///
/// Fails if deserialization fails (see enum docs for more info).
pub fn from_json(json: serde_json::Value) -> serde_json::Result<Self> {
json.try_into()
}
}
impl Default for ConstValue {
fn default() -> Self {
Self::Null
}
}
impl Display for ConstValue {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Number(num) => write!(f, "{}", *num),
Self::String(val) => write_quoted(val, f),
Self::Boolean(true) => f.write_str("true"),
Self::Boolean(false) => f.write_str("false"),
Self::Null => f.write_str("null"),
Self::Enum(name) => f.write_str(name),
Self::List(items) => write_list(items, f),
Self::Object(map) => write_object(map, f),
}
}
}
impl TryFrom<serde_json::Value> for ConstValue {
type Error = serde_json::Error;
fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
Self::deserialize(value)
}
}
impl TryFrom<ConstValue> for serde_json::Value {
type Error = serde_json::Error;
fn try_from(value: ConstValue) -> Result<Self, Self::Error> {
serde_json::to_value(value)
}
}
/// A GraphQL value, for example `1`, `$name` or `"Hello World!"`. This is
/// [`ConstValue`](enum.ConstValue.html) with variables.
///
/// It can be serialized and deserialized. Enums will be converted to strings. Attempting to
/// serialize `Upload` or `Variable` will fail, and `Enum`, `Upload` and `Variable` cannot be
/// deserialized.
///
/// [Reference](https://spec.graphql.org/June2018/#Value).
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(untagged)]
pub enum Value {
/// A variable, without the `$`.
#[serde(serialize_with = "fail_serialize_variable", skip_deserializing)]
Variable(Name),
/// `null`.
Null,
/// A number.
Number(Number),
/// A string.
String(String),
/// A boolean.
Boolean(bool),
/// An enum. These are typically in `SCREAMING_SNAKE_CASE`.
#[serde(skip_deserializing)]
Enum(Name),
/// A list of values.
List(Vec<Value>),
/// An object. This is a map of keys to values.
Object(BTreeMap<Name, Value>),
}
impl Value {
/// Attempt to convert the value into a const value by using a function to get a variable.
pub fn into_const_with<E>(
self,
mut f: impl FnMut(Name) -> Result<ConstValue, E>,
) -> Result<ConstValue, E> {
self.into_const_with_mut(&mut f)
}
fn into_const_with_mut<E>(
self,
f: &mut impl FnMut(Name) -> Result<ConstValue, E>,
) -> Result<ConstValue, E> {
Ok(match self {
Self::Variable(name) => f(name)?,
Self::Null => ConstValue::Null,
Self::Number(num) => ConstValue::Number(num),
Self::String(s) => ConstValue::String(s),
Self::Boolean(b) => ConstValue::Boolean(b),
Self::Enum(v) => ConstValue::Enum(v),
Self::List(items) => ConstValue::List(
items
.into_iter()
.map(|value| value.into_const_with_mut(f))
.collect::<Result<_, _>>()?,
),
Self::Object(map) => ConstValue::Object(
map.into_iter()
.map(|(key, value)| Ok((key, value.into_const_with_mut(f)?)))
.collect::<Result<_, _>>()?,
),
})
}
/// Attempt to convert the value into a const value.
///
/// Will fail if the value contains variables.
#[must_use]
pub fn into_const(self) -> Option<ConstValue> {
self.into_const_with(|_| Err(())).ok()
}
/// Attempt to convert the value into JSON. This is equivalent to the `TryFrom` implementation.
///
/// # Errors
///
/// Fails if serialization fails (see enum docs for more info).
pub fn into_json(self) -> serde_json::Result<serde_json::Value> {
self.try_into()
}
/// Attempt to convert JSON into a value. This is equivalent to the `TryFrom` implementation.
///
/// # Errors
///
/// Fails if deserialization fails (see enum docs for more info).
pub fn from_json(json: serde_json::Value) -> serde_json::Result<Self> {
json.try_into()
}
}
impl Default for Value {
fn default() -> Self {
Self::Null
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Variable(name) => write!(f, "${}", name),
Self::Number(num) => write!(f, "{}", *num),
Self::String(val) => write_quoted(val, f),
Self::Boolean(true) => f.write_str("true"),
Self::Boolean(false) => f.write_str("false"),
Self::Null => f.write_str("null"),
Self::Enum(name) => f.write_str(name),
Self::List(items) => write_list(items, f),
Self::Object(map) => write_object(map, f),
}
}
}
impl From<ConstValue> for Value {
fn from(value: ConstValue) -> Self {
value.into_value()
}
}
impl TryFrom<serde_json::Value> for Value {
type Error = serde_json::Error;
fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
Self::deserialize(value)
}
}
impl TryFrom<Value> for serde_json::Value {
type Error = serde_json::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
serde_json::to_value(value)
}
}
fn fail_serialize_variable<S: Serializer>(_: &str, _: S) -> Result<S::Ok, S::Error> {
Err(S::Error::custom("cannot serialize variable"))
}
fn write_quoted(s: &str, f: &mut Formatter<'_>) -> fmt::Result {
f.write_char('"')?;
for c in s.chars() {
match c {
'\r' => f.write_str("\\r"),
'\n' => f.write_str("\\n"),
'\t' => f.write_str("\\t"),
'"' => f.write_str("\\\""),
'\\' => f.write_str("\\\\"),
c if c.is_control() => write!(f, "\\u{:04}", c as u32),
c => f.write_char(c),
}?
}
f.write_char('"')
}
fn write_list<T: Display>(list: impl IntoIterator<Item = T>, f: &mut Formatter<'_>) -> fmt::Result {
f.write_char('[')?;
for item in list {
item.fmt(f)?;
f.write_char(',')?;
}
f.write_char(']')
}
fn write_object<K: Display, V: Display>(
object: impl IntoIterator<Item = (K, V)>,
f: &mut Formatter<'_>,
) -> fmt::Result {
f.write_char('{')?;
for (name, value) in object {
write!(f, "{}: {},", name, value)?;
}
f.write_char('}')
}
/// A const GraphQL directive, such as `@deprecated(reason: "Use the other field)`. This differs
/// from [`Directive`](struct.Directive.html) in that it uses [`ConstValue`](enum.ConstValue.html)
/// instead of [`Value`](enum.Value.html).
@ -575,93 +174,3 @@ impl Directive {
.map(|item| &item.1)
}
}
/// A GraphQL name.
///
/// [Reference](https://spec.graphql.org/June2018/#Name).
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Name(Arc<str>);
impl Serialize for Name {
fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
serializer.serialize_str(&self.0)
}
}
impl Name {
/// Create a new name.
pub fn new(name: &str) -> Self {
Self(name.into())
}
/// Get the name as a string.
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl AsRef<str> for Name {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Borrow<str> for Name {
fn borrow(&self) -> &str {
&self.0
}
}
impl Deref for Name {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Display for Name {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl PartialEq<String> for Name {
fn eq(&self, other: &String) -> bool {
self.as_str() == other
}
}
impl PartialEq<str> for Name {
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl PartialEq<Name> for String {
fn eq(&self, other: &Name) -> bool {
self == other.as_str()
}
}
impl PartialEq<Name> for str {
fn eq(&self, other: &Name) -> bool {
other == self
}
}
impl<'a> PartialEq<&'a str> for Name {
fn eq(&self, other: &&'a str) -> bool {
self == *other
}
}
impl<'a> PartialEq<Name> for &'a str {
fn eq(&self, other: &Name) -> bool {
other == self
}
}
impl<'de> Deserialize<'de> for Name {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Ok(Self(
String::deserialize(deserializer)?.into_boxed_str().into(),
))
}
}

View File

@ -1,6 +1,7 @@
//! Service-related GraphQL types.
use super::*;
use async_graphql_value::Name;
/// An GraphQL file or request string defining a GraphQL service.
///

View File

@ -1,13 +1,13 @@
use crate::extensions::Extensions;
use crate::parser::types::{
Directive, Field, FragmentDefinition, Name, OperationDefinition, SelectionSet,
Value as InputValue,
Directive, Field, FragmentDefinition, OperationDefinition, SelectionSet,
};
use crate::schema::SchemaEnv;
use crate::{
Error, InputValueType, Lookahead, Pos, Positioned, Result, ServerError, ServerResult,
UploadValue, Value,
};
use async_graphql_value::{Name, Value as InputValue};
use fnv::FnvHashMap;
use serde::ser::{SerializeSeq, Serializer};
use serde::{Deserialize, Serialize};

View File

@ -18,8 +18,8 @@ pub use self::apollo_tracing::ApolloTracing;
pub use self::logger::Logger;
#[cfg(feature = "tracing")]
pub use self::tracing::Tracing;
use crate::parser::types::{ExecutableDocument, Name};
use crate::{Error, Value};
use crate::parser::types::ExecutableDocument;
use crate::{Error, Name, Value};
use std::any::{Any, TypeId};
use std::collections::BTreeMap;

View File

@ -155,6 +155,9 @@ pub use static_assertions;
pub use subscription::SubscriptionType;
pub use async_graphql_parser as parser;
pub use async_graphql_value::{
from_value, to_value, ConstValue as Value, DeserializerError, Name, Number, SerializerError,
};
pub use base::{
InputObjectType, InputValueType, InterfaceType, ObjectType, OutputValueType, Type, UnionType,
};
@ -166,7 +169,6 @@ pub use error::{
ParseRequestError, PathSegment, Result, ResultExt, ServerError, ServerResult,
};
pub use look_ahead::Lookahead;
pub use parser::types::{ConstValue as Value, Number};
pub use registry::CacheControl;
pub use request::{BatchRequest, Request};
pub use resolver_utils::{ContainerType, EnumType, ScalarType};

View File

@ -1,5 +1,5 @@
use crate::parser::types::{Field, FragmentDefinition, Name, Selection, SelectionSet};
use crate::Positioned;
use crate::parser::types::{Field, FragmentDefinition, Selection, SelectionSet};
use crate::{Name, Positioned};
use std::collections::HashMap;
/// A selection performed by a query.

View File

@ -1,8 +1,9 @@
use crate::extensions::{ErrorLogger, Extension, ExtensionContext, ResolveInfo};
use crate::parser::types::{Name, Selection};
use crate::parser::types::Selection;
use crate::registry::MetaType;
use crate::{
Context, ContextSelectionSet, OutputValueType, PathSegment, ServerError, ServerResult, Value,
Context, ContextSelectionSet, Name, OutputValueType, PathSegment, ServerError, ServerResult,
Value,
};
use std::collections::BTreeMap;
use std::future::Future;

View File

@ -1,5 +1,4 @@
use crate::parser::types::Name;
use crate::{InputValueError, InputValueResult, InputValueType, Type, Value};
use crate::{InputValueError, InputValueResult, InputValueType, Name, Type, Value};
/// A variant of an enum.
pub struct EnumItem<T> {

View File

@ -1,5 +1,7 @@
use crate::parser::types::{Name, Selection, TypeCondition};
use crate::{Context, ContextSelectionSet, PathSegment, ServerError, ServerResult, Type, Value};
use crate::parser::types::{Selection, TypeCondition};
use crate::{
Context, ContextSelectionSet, Name, PathSegment, ServerError, ServerResult, Type, Value,
};
use futures::{Stream, StreamExt};
use std::pin::Pin;

View File

@ -1,6 +1,6 @@
use crate::parser::types::Name;
use crate::{
InputValueError, InputValueResult, InputValueType, OutputValueType, Scalar, ScalarType, Value,
InputValueError, InputValueResult, InputValueType, Name, OutputValueType, Scalar, ScalarType,
Value,
};
use std::collections::BTreeMap;

View File

@ -1,6 +1,6 @@
use crate::parser::types::Name;
use crate::{
InputValueError, InputValueResult, InputValueType, OutputValueType, Scalar, ScalarType, Value,
InputValueError, InputValueResult, InputValueType, Name, OutputValueType, Scalar, ScalarType,
Value,
};
use std::collections::{BTreeMap, HashMap};

View File

@ -1,9 +1,10 @@
use crate::context::QueryPathNode;
use crate::parser::types::{Directive, Field, Name, Value};
use crate::parser::types::{Directive, Field};
use crate::registry::MetaInputValue;
use crate::validation::utils::is_valid_input_value;
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::{Positioned, QueryPathSegment};
use crate::{Name, Positioned, QueryPathSegment};
use async_graphql_value::Value;
use indexmap::map::IndexMap;
#[derive(Default)]

View File

@ -1,6 +1,6 @@
use crate::parser::types::{FragmentDefinition, InlineFragment, Name};
use crate::parser::types::{FragmentDefinition, InlineFragment};
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::Positioned;
use crate::{Name, Positioned};
#[derive(Default)]
pub struct FragmentsOnCompositeTypes;

View File

@ -1,8 +1,9 @@
use crate::parser::types::{Directive, Field, Name, Value};
use crate::parser::types::{Directive, Field};
use crate::registry::MetaInputValue;
use crate::validation::suggestion::make_suggestion;
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::Positioned;
use crate::{Name, Positioned};
use async_graphql_value::Value;
use indexmap::map::IndexMap;
enum ArgsType<'a> {

View File

@ -1,10 +1,10 @@
use crate::model::__DirectiveLocation;
use crate::parser::types::{
Directive, Field, FragmentDefinition, FragmentSpread, InlineFragment, Name,
OperationDefinition, OperationType,
Directive, Field, FragmentDefinition, FragmentSpread, InlineFragment, OperationDefinition,
OperationType,
};
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::Positioned;
use crate::{Name, Positioned};
#[derive(Default)]
pub struct KnownDirectives {

View File

@ -1,9 +1,7 @@
use crate::parser::types::{
FragmentDefinition, InlineFragment, Name, TypeCondition, VariableDefinition,
};
use crate::parser::types::{FragmentDefinition, InlineFragment, TypeCondition, VariableDefinition};
use crate::registry::MetaTypeName;
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::{Pos, Positioned};
use crate::{Name, Pos, Positioned};
#[derive(Default)]
pub struct KnownTypeNames;

View File

@ -1,6 +1,6 @@
use crate::parser::types::{ExecutableDocument, FragmentDefinition, FragmentSpread, Name};
use crate::parser::types::{ExecutableDocument, FragmentDefinition, FragmentSpread};
use crate::validation::visitor::{RuleError, Visitor, VisitorContext};
use crate::{Pos, Positioned};
use crate::{Name, Pos, Positioned};
use std::collections::{HashMap, HashSet};
struct CycleDetector<'a> {

View File

@ -1,10 +1,10 @@
use crate::parser::types::{
ExecutableDocument, FragmentDefinition, FragmentSpread, Name, OperationDefinition, Value,
VariableDefinition,
ExecutableDocument, FragmentDefinition, FragmentSpread, OperationDefinition, VariableDefinition,
};
use crate::validation::utils::{referenced_variables, Scope};
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::{Pos, Positioned};
use crate::{Name, Pos, Positioned};
use async_graphql_value::Value;
use std::collections::{HashMap, HashSet};
#[derive(Default)]

View File

@ -1,9 +1,9 @@
use crate::parser::types::{
ExecutableDocument, FragmentDefinition, FragmentSpread, Name, OperationDefinition,
ExecutableDocument, FragmentDefinition, FragmentSpread, OperationDefinition,
};
use crate::validation::utils::Scope;
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::{Pos, Positioned};
use crate::{Name, Pos, Positioned};
use std::collections::{HashMap, HashSet};
#[derive(Default)]

View File

@ -1,10 +1,10 @@
use crate::parser::types::{
ExecutableDocument, FragmentDefinition, FragmentSpread, Name, OperationDefinition, Value,
VariableDefinition,
ExecutableDocument, FragmentDefinition, FragmentSpread, OperationDefinition, VariableDefinition,
};
use crate::validation::utils::{referenced_variables, Scope};
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::{Pos, Positioned};
use crate::{Name, Pos, Positioned};
use async_graphql_value::Value;
use std::collections::{HashMap, HashSet};
#[derive(Default)]

View File

@ -1,6 +1,7 @@
use crate::parser::types::{Directive, Field, Name, Value};
use crate::parser::types::{Directive, Field};
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::Positioned;
use crate::{Name, Positioned};
use async_graphql_value::Value;
use std::collections::HashSet;
#[derive(Default)]

View File

@ -1,6 +1,6 @@
use crate::parser::types::{Name, OperationDefinition, VariableDefinition};
use crate::parser::types::{OperationDefinition, VariableDefinition};
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::Positioned;
use crate::{Name, Positioned};
use std::collections::HashSet;
#[derive(Default)]

View File

@ -1,6 +1,6 @@
use crate::parser::types::{Name, OperationDefinition, OperationType};
use crate::parser::types::{OperationDefinition, OperationType};
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::Positioned;
use crate::{Name, Positioned};
#[derive(Default)]
pub struct UploadFile;

View File

@ -1,11 +1,11 @@
use crate::parser::types::{
ExecutableDocument, FragmentDefinition, FragmentSpread, Name, OperationDefinition, Value,
VariableDefinition,
ExecutableDocument, FragmentDefinition, FragmentSpread, OperationDefinition, VariableDefinition,
};
use crate::registry::MetaTypeName;
use crate::validation::utils::Scope;
use crate::validation::visitor::{Visitor, VisitorContext};
use crate::{Pos, Positioned};
use crate::{Name, Pos, Positioned};
use async_graphql_value::Value;
use std::collections::{HashMap, HashSet};
#[derive(Default)]

View File

@ -1,6 +1,6 @@
use crate::context::QueryPathNode;
use crate::parser::types::{ConstValue, Value};
use crate::{registry, QueryPathSegment};
use async_graphql_value::{ConstValue, Value};
use std::collections::HashSet;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]

View File

@ -1,10 +1,10 @@
use crate::parser::types::{
Directive, ExecutableDocument, Field, FragmentDefinition, FragmentSpread, InlineFragment, Name,
OperationDefinition, OperationType, Selection, SelectionSet, TypeCondition, Value,
VariableDefinition,
Directive, ExecutableDocument, Field, FragmentDefinition, FragmentSpread, InlineFragment,
OperationDefinition, OperationType, Selection, SelectionSet, TypeCondition, VariableDefinition,
};
use crate::registry::{self, MetaType, MetaTypeName};
use crate::{Pos, Positioned, ServerError, Variables};
use crate::{Name, Pos, Positioned, ServerError, Variables};
use async_graphql_value::Value;
use std::collections::HashMap;
use std::fmt::{self, Display, Formatter};

View File

@ -3,7 +3,6 @@ use async_graphql::validators::{
ListMinLength, StringMaxLength, StringMinLength, MAC,
};
use async_graphql::*;
use async_graphql_parser::types::Name;
#[async_std::test]
pub async fn test_input_validator_string_min_length() {

17
value/Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "async-graphql-value"
version = "2.0.0-alpha.24"
authors = ["sunli <scott_s829@163.com>", "Koxiaet"]
edition = "2018"
description = "GraphQL value for async-graphql"
publish = true
license = "MIT/Apache-2.0"
documentation = "https://docs.rs/async-graphql/"
homepage = "https://github.com/async-graphql/async-graphql"
repository = "https://github.com/async-graphql/async-graphql"
keywords = ["futures", "async", "graphql"]
categories = ["network-programming", "asynchronous"]
[dependencies]
serde_json = "1.0.57"
serde = { version = "1.0.115", features = ["derive"] }

533
value/src/de.rs Normal file
View File

@ -0,0 +1,533 @@
use crate::{ConstValue, Name};
use serde::de::{
self, Deserialize, DeserializeOwned, DeserializeSeed, EnumAccess, Error as DeError,
IntoDeserializer, MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor,
};
use serde::forward_to_deserialize_any;
use std::collections::BTreeMap;
use std::{fmt, vec};
#[derive(Debug)]
pub enum DeserializerError {
Custom(String),
}
impl de::Error for DeserializerError {
fn custom<T: fmt::Display>(msg: T) -> Self {
DeserializerError::Custom(msg.to_string())
}
}
impl std::error::Error for DeserializerError {
fn description(&self) -> &str {
"Value deserializer error"
}
}
impl fmt::Display for DeserializerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
DeserializerError::Custom(ref msg) => write!(f, "{}", msg),
}
}
}
impl From<de::value::Error> for DeserializerError {
fn from(e: de::value::Error) -> DeserializerError {
DeserializerError::Custom(e.to_string())
}
}
impl ConstValue {
fn unexpected(&self) -> Unexpected {
match self {
ConstValue::Null => Unexpected::Unit,
ConstValue::Number(_) => Unexpected::Other("number"),
ConstValue::String(v) => Unexpected::Str(v),
ConstValue::Boolean(v) => Unexpected::Bool(*v),
ConstValue::Enum(v) => Unexpected::Str(v),
ConstValue::List(_) => Unexpected::Seq,
ConstValue::Object(_) => Unexpected::Map,
}
}
}
fn visit_array<'de, V>(array: Vec<ConstValue>, visitor: V) -> Result<V::Value, DeserializerError>
where
V: Visitor<'de>,
{
let len = array.len();
let mut deserializer = SeqDeserializer::new(array);
let seq = visitor.visit_seq(&mut deserializer)?;
let remaining = deserializer.iter.len();
if remaining == 0 {
Ok(seq)
} else {
Err(DeserializerError::invalid_length(
len,
&"fewer elements in array",
))
}
}
fn visit_object<'de, V>(
object: BTreeMap<Name, ConstValue>,
visitor: V,
) -> Result<V::Value, DeserializerError>
where
V: Visitor<'de>,
{
let len = object.len();
let mut deserializer = MapDeserializer::new(object);
let map = visitor.visit_map(&mut deserializer)?;
let remaining = deserializer.iter.len();
if remaining == 0 {
Ok(map)
} else {
Err(DeserializerError::invalid_length(
len,
&"fewer elements in map",
))
}
}
impl<'de> de::Deserializer<'de> for ConstValue {
type Error = DeserializerError;
fn deserialize_any<V>(self, visitor: V) -> Result<<V as Visitor<'de>>::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
ConstValue::Null => visitor.visit_unit(),
ConstValue::Number(v) => v
.deserialize_any(visitor)
.map_err(|err| DeserializerError::Custom(err.to_string())),
ConstValue::String(v) => visitor.visit_str(&v),
ConstValue::Boolean(v) => visitor.visit_bool(v),
ConstValue::Enum(v) => visitor.visit_str(v.as_str()),
ConstValue::List(v) => visit_array(v, visitor),
ConstValue::Object(v) => visit_object(v, visitor),
}
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf unit unit_struct seq tuple
tuple_struct map struct identifier ignored_any
}
fn deserialize_option<V>(self, visitor: V) -> Result<<V as Visitor<'de>>::Value, Self::Error>
where
V: Visitor<'de>,
{
match self {
ConstValue::Null => visitor.visit_none(),
_ => visitor.visit_some(self),
}
}
fn deserialize_newtype_struct<V>(
self,
_name: &'static str,
visitor: V,
) -> Result<<V as Visitor<'de>>::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<<V as Visitor<'de>>::Value, Self::Error>
where
V: Visitor<'de>,
{
let (variant, value) = match self {
ConstValue::Object(value) => {
let mut iter = value.into_iter();
let (variant, value) = match iter.next() {
Some(v) => v,
None => {
return Err(serde::de::Error::invalid_value(
Unexpected::Map,
&"map with a single key",
));
}
};
// enums are encoded in json as maps with a single key:value pair
if iter.next().is_some() {
return Err(serde::de::Error::invalid_value(
Unexpected::Map,
&"map with a single key",
));
}
(variant, Some(value))
}
ConstValue::String(variant) => (Name::new(&variant), None),
ConstValue::Enum(variant) => (variant, None),
other => {
return Err(DeserializerError::invalid_type(
other.unexpected(),
&"string or map",
));
}
};
visitor.visit_enum(EnumDeserializer { variant, value })
}
}
struct EnumDeserializer {
variant: Name,
value: Option<ConstValue>,
}
impl<'de> EnumAccess<'de> for EnumDeserializer {
type Error = DeserializerError;
type Variant = VariantDeserializer;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, VariantDeserializer), DeserializerError>
where
V: DeserializeSeed<'de>,
{
let variant = self.variant.into_deserializer();
let visitor = VariantDeserializer { value: self.value };
seed.deserialize(variant).map(|v| (v, visitor))
}
}
impl<'de> IntoDeserializer<'de, DeserializerError> for ConstValue {
type Deserializer = Self;
fn into_deserializer(self) -> Self::Deserializer {
self
}
}
struct VariantDeserializer {
value: Option<ConstValue>,
}
impl<'de> VariantAccess<'de> for VariantDeserializer {
type Error = DeserializerError;
fn unit_variant(self) -> Result<(), DeserializerError> {
match self.value {
Some(value) => Deserialize::deserialize(value),
None => Ok(()),
}
}
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, DeserializerError>
where
T: DeserializeSeed<'de>,
{
match self.value {
Some(value) => seed.deserialize(value),
None => Err(DeserializerError::invalid_type(
Unexpected::UnitVariant,
&"newtype variant",
)),
}
}
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, DeserializerError>
where
V: Visitor<'de>,
{
match self.value {
Some(ConstValue::List(v)) => {
serde::Deserializer::deserialize_any(SeqDeserializer::new(v), visitor)
}
Some(other) => Err(serde::de::Error::invalid_type(
other.unexpected(),
&"tuple variant",
)),
None => Err(DeserializerError::invalid_type(
Unexpected::UnitVariant,
&"tuple variant",
)),
}
}
fn struct_variant<V>(
self,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, DeserializerError>
where
V: Visitor<'de>,
{
match self.value {
Some(ConstValue::Object(v)) => {
serde::Deserializer::deserialize_any(MapDeserializer::new(v), visitor)
}
Some(other) => Err(DeserializerError::invalid_type(
other.unexpected(),
&"struct variant",
)),
None => Err(DeserializerError::invalid_type(
Unexpected::UnitVariant,
&"struct variant",
)),
}
}
}
struct SeqDeserializer {
iter: vec::IntoIter<ConstValue>,
}
impl SeqDeserializer {
fn new(vec: Vec<ConstValue>) -> Self {
SeqDeserializer {
iter: vec.into_iter(),
}
}
}
impl<'de> serde::Deserializer<'de> for SeqDeserializer {
type Error = DeserializerError;
#[inline]
fn deserialize_any<V>(mut self, visitor: V) -> Result<V::Value, DeserializerError>
where
V: Visitor<'de>,
{
let len = self.iter.len();
if len == 0 {
visitor.visit_unit()
} else {
let ret = visitor.visit_seq(&mut self)?;
let remaining = self.iter.len();
if remaining == 0 {
Ok(ret)
} else {
Err(DeserializerError::invalid_length(
len,
&"fewer elements in array",
))
}
}
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
impl<'de> SeqAccess<'de> for SeqDeserializer {
type Error = DeserializerError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, DeserializerError>
where
T: DeserializeSeed<'de>,
{
match self.iter.next() {
Some(value) => seed.deserialize(value).map(Some),
None => Ok(None),
}
}
fn size_hint(&self) -> Option<usize> {
match self.iter.size_hint() {
(lower, Some(upper)) if lower == upper => Some(upper),
_ => None,
}
}
}
struct MapDeserializer {
iter: <BTreeMap<Name, ConstValue> as IntoIterator>::IntoIter,
value: Option<ConstValue>,
}
impl MapDeserializer {
fn new(map: BTreeMap<Name, ConstValue>) -> Self {
MapDeserializer {
iter: map.into_iter(),
value: None,
}
}
}
impl<'de> MapAccess<'de> for MapDeserializer {
type Error = DeserializerError;
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, DeserializerError>
where
T: DeserializeSeed<'de>,
{
match self.iter.next() {
Some((key, value)) => {
self.value = Some(value);
let key_de = MapKeyDeserializer { key };
seed.deserialize(key_de).map(Some)
}
None => Ok(None),
}
}
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, DeserializerError>
where
T: DeserializeSeed<'de>,
{
match self.value.take() {
Some(value) => seed.deserialize(value),
None => Err(serde::de::Error::custom("value is missing")),
}
}
fn size_hint(&self) -> Option<usize> {
match self.iter.size_hint() {
(lower, Some(upper)) if lower == upper => Some(upper),
_ => None,
}
}
}
impl<'de> serde::Deserializer<'de> for MapDeserializer {
type Error = DeserializerError;
#[inline]
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, DeserializerError>
where
V: Visitor<'de>,
{
visitor.visit_map(self)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
struct MapKeyDeserializer {
key: Name,
}
impl<'de> serde::Deserializer<'de> for MapKeyDeserializer {
type Error = DeserializerError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, DeserializerError>
where
V: Visitor<'de>,
{
NameDeserializer::new(self.key).deserialize_any(visitor)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string
bytes byte_buf unit unit_struct seq tuple option newtype_struct enum
tuple_struct map struct identifier ignored_any
}
}
struct NameDeserializer {
value: Name,
}
impl NameDeserializer {
fn new(value: Name) -> Self {
NameDeserializer { value }
}
}
impl<'de> de::Deserializer<'de> for NameDeserializer {
type Error = DeserializerError;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, DeserializerError>
where
V: de::Visitor<'de>,
{
visitor.visit_string(self.value.to_string())
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple enum
tuple_struct map struct identifier ignored_any
}
}
/// Interpret a `ConstValue` as an instance of type `T`.
pub fn from_value<T: DeserializeOwned>(value: ConstValue) -> Result<T, DeserializerError> {
T::deserialize(value)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Number;
use serde::Deserialize;
#[test]
fn test_deserializer() {
let n: bool = from_value(ConstValue::Boolean(true)).unwrap();
assert_eq!(n, true);
let n: i32 = from_value(ConstValue::Number(100i32.into())).unwrap();
assert_eq!(n, 100);
let n: f32 = from_value(ConstValue::Number(Number::from_f64(1.123f64).unwrap())).unwrap();
assert_eq!(n, 1.123);
let n: Option<i32> = from_value(ConstValue::Number(100i32.into())).unwrap();
assert_eq!(n, Some(100));
let n: Option<i32> = from_value(ConstValue::Null).unwrap();
assert_eq!(n, None);
let n: Vec<i32> = from_value(
(0..10)
.into_iter()
.map(|v| ConstValue::Number(v.into()))
.collect(),
)
.unwrap();
assert_eq!(n, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
#[derive(Deserialize)]
struct NewType(i32);
let n: NewType = from_value(ConstValue::Number(100i32.into())).unwrap();
assert_eq!(n.0, 100);
#[derive(Deserialize, Debug, Eq, PartialEq)]
enum Enum {
A,
B,
}
let n: Enum = from_value(ConstValue::String("A".to_string())).unwrap();
assert_eq!(n, Enum::A);
let n: Enum = from_value(ConstValue::Enum(Name::new("B"))).unwrap();
assert_eq!(n, Enum::B);
#[derive(Deserialize, Debug, Eq, PartialEq)]
struct Struct {
a: i32,
b: Option<Enum>,
}
let mut obj = BTreeMap::<Name, ConstValue>::new();
obj.insert(Name::new("a"), ConstValue::Number(10.into()));
obj.insert(Name::new("b"), ConstValue::Enum(Name::new("B")));
let n: Struct = from_value(ConstValue::Object(obj)).unwrap();
assert_eq!(
n,
Struct {
a: 10,
b: Some(Enum::B)
}
);
}
}

499
value/src/lib.rs Normal file
View File

@ -0,0 +1,499 @@
mod de;
mod ser;
use serde::ser::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::{Borrow, Cow};
use std::collections::BTreeMap;
use std::convert::{TryFrom, TryInto};
use std::fmt::{self, Display, Formatter, Write};
use std::iter::FromIterator;
use std::ops::Deref;
use std::sync::Arc;
pub use de::{from_value, DeserializerError};
pub use ser::{to_value, SerializerError};
pub use serde_json::Number;
/// A GraphQL name.
///
/// [Reference](https://spec.graphql.org/June2018/#Name).
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Name(Arc<str>);
impl Serialize for Name {
fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
serializer.serialize_str(&self.0)
}
}
impl Name {
/// Create a new name.
pub fn new(name: &str) -> Self {
Self(name.into())
}
/// Get the name as a string.
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl AsRef<str> for Name {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Borrow<str> for Name {
fn borrow(&self) -> &str {
&self.0
}
}
impl Deref for Name {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Display for Name {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl PartialEq<String> for Name {
fn eq(&self, other: &String) -> bool {
self.as_str() == other
}
}
impl PartialEq<str> for Name {
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl PartialEq<Name> for String {
fn eq(&self, other: &Name) -> bool {
self == other.as_str()
}
}
impl PartialEq<Name> for str {
fn eq(&self, other: &Name) -> bool {
other == self
}
}
impl<'a> PartialEq<&'a str> for Name {
fn eq(&self, other: &&'a str) -> bool {
self == *other
}
}
impl<'a> PartialEq<Name> for &'a str {
fn eq(&self, other: &Name) -> bool {
other == self
}
}
impl<'de> Deserialize<'de> for Name {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Ok(Self(
String::deserialize(deserializer)?.into_boxed_str().into(),
))
}
}
/// A resolved GraphQL value, for example `1` or `"Hello World!"`.
///
/// It can be serialized and deserialized. Enums will be converted to strings. Attempting to
/// serialize `Upload` will fail, and `Enum` and `Upload` cannot be deserialized.
///
/// [Reference](https://spec.graphql.org/June2018/#Value).
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ConstValue {
/// `null`.
Null,
/// A number.
Number(Number),
/// A string.
String(String),
/// A boolean.
Boolean(bool),
/// An enum. These are typically in `SCREAMING_SNAKE_CASE`.
#[serde(skip_deserializing)]
Enum(Name),
/// A list of values.
List(Vec<ConstValue>),
/// An object. This is a map of keys to values.
Object(BTreeMap<Name, ConstValue>),
}
impl From<()> for ConstValue {
fn from((): ()) -> Self {
ConstValue::Null
}
}
macro_rules! from_integer {
($($ty:ident),*) => {
$(
impl From<$ty> for ConstValue {
fn from(n: $ty) -> Self {
ConstValue::Number(n.into())
}
}
)*
};
}
from_integer!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
impl From<f32> for ConstValue {
fn from(f: f32) -> Self {
From::from(f as f64)
}
}
impl From<f64> for ConstValue {
fn from(f: f64) -> Self {
Number::from_f64(f).map_or(ConstValue::Null, ConstValue::Number)
}
}
impl From<bool> for ConstValue {
fn from(value: bool) -> Self {
ConstValue::Boolean(value)
}
}
impl From<String> for ConstValue {
fn from(value: String) -> Self {
ConstValue::String(value)
}
}
impl<'a> From<&'a str> for ConstValue {
fn from(value: &'a str) -> Self {
ConstValue::String(value.into())
}
}
impl<'a> From<Cow<'a, str>> for ConstValue {
fn from(f: Cow<'a, str>) -> Self {
ConstValue::String(f.into_owned())
}
}
impl<T: Into<ConstValue>> FromIterator<T> for ConstValue {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
ConstValue::List(iter.into_iter().map(Into::into).collect())
}
}
impl<'a, T: Clone + Into<ConstValue>> From<&'a [T]> for ConstValue {
fn from(f: &'a [T]) -> Self {
ConstValue::List(f.iter().cloned().map(Into::into).collect())
}
}
impl<T: Into<ConstValue>> From<Vec<T>> for ConstValue {
fn from(f: Vec<T>) -> Self {
ConstValue::List(f.into_iter().map(Into::into).collect())
}
}
impl From<BTreeMap<Name, ConstValue>> for ConstValue {
fn from(f: BTreeMap<Name, ConstValue>) -> Self {
ConstValue::Object(f)
}
}
impl PartialEq<serde_json::Value> for ConstValue {
fn eq(&self, other: &serde_json::Value) -> bool {
match (self, other) {
(ConstValue::Null, serde_json::Value::Null) => true,
(ConstValue::Number(a), serde_json::Value::Number(b)) => a == b,
(ConstValue::String(a), serde_json::Value::String(b)) => a == b,
(ConstValue::Boolean(a), serde_json::Value::Bool(b)) => a == b,
(ConstValue::Enum(a), serde_json::Value::String(b)) => a == b,
(ConstValue::List(a), serde_json::Value::Array(b)) => {
if a.len() != b.len() {
return false;
}
a.iter().zip(b.iter()).all(|(a, b)| a == b)
}
(ConstValue::Object(a), serde_json::Value::Object(b)) => {
if a.len() != b.len() {
return false;
}
for (a_key, a_value) in a.iter() {
if let Some(b_value) = b.get(a_key.as_str()) {
if b_value != a_value {
return false;
}
} else {
return false;
}
}
true
}
_ => false,
}
}
}
impl PartialEq<ConstValue> for serde_json::Value {
fn eq(&self, other: &ConstValue) -> bool {
other == self
}
}
impl ConstValue {
/// Convert this `ConstValue` into a `Value`.
#[must_use]
pub fn into_value(self) -> Value {
match self {
Self::Null => Value::Null,
Self::Number(num) => Value::Number(num),
Self::String(s) => Value::String(s),
Self::Boolean(b) => Value::Boolean(b),
Self::Enum(v) => Value::Enum(v),
Self::List(items) => {
Value::List(items.into_iter().map(ConstValue::into_value).collect())
}
Self::Object(map) => Value::Object(
map.into_iter()
.map(|(key, value)| (key, value.into_value()))
.collect(),
),
}
}
/// Attempt to convert the value into JSON. This is equivalent to the `TryFrom` implementation.
///
/// # Errors
///
/// Fails if serialization fails (see enum docs for more info).
pub fn into_json(self) -> serde_json::Result<serde_json::Value> {
self.try_into()
}
/// Attempt to convert JSON into a value. This is equivalent to the `TryFrom` implementation.
///
/// # Errors
///
/// Fails if deserialization fails (see enum docs for more info).
pub fn from_json(json: serde_json::Value) -> serde_json::Result<Self> {
json.try_into()
}
}
impl Default for ConstValue {
fn default() -> Self {
Self::Null
}
}
impl Display for ConstValue {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Number(num) => write!(f, "{}", *num),
Self::String(val) => write_quoted(val, f),
Self::Boolean(true) => f.write_str("true"),
Self::Boolean(false) => f.write_str("false"),
Self::Null => f.write_str("null"),
Self::Enum(name) => f.write_str(name),
Self::List(items) => write_list(items, f),
Self::Object(map) => write_object(map, f),
}
}
}
impl TryFrom<serde_json::Value> for ConstValue {
type Error = serde_json::Error;
fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
Self::deserialize(value)
}
}
impl TryFrom<ConstValue> for serde_json::Value {
type Error = serde_json::Error;
fn try_from(value: ConstValue) -> Result<Self, Self::Error> {
serde_json::to_value(value)
}
}
/// A GraphQL value, for example `1`, `$name` or `"Hello World!"`. This is
/// [`ConstValue`](enum.ConstValue.html) with variables.
///
/// It can be serialized and deserialized. Enums will be converted to strings. Attempting to
/// serialize `Upload` or `Variable` will fail, and `Enum`, `Upload` and `Variable` cannot be
/// deserialized.
///
/// [Reference](https://spec.graphql.org/June2018/#Value).
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(untagged)]
pub enum Value {
/// A variable, without the `$`.
#[serde(serialize_with = "fail_serialize_variable", skip_deserializing)]
Variable(Name),
/// `null`.
Null,
/// A number.
Number(Number),
/// A string.
String(String),
/// A boolean.
Boolean(bool),
/// An enum. These are typically in `SCREAMING_SNAKE_CASE`.
#[serde(skip_deserializing)]
Enum(Name),
/// A list of values.
List(Vec<Value>),
/// An object. This is a map of keys to values.
Object(BTreeMap<Name, Value>),
}
impl Value {
/// Attempt to convert the value into a const value by using a function to get a variable.
pub fn into_const_with<E>(
self,
mut f: impl FnMut(Name) -> Result<ConstValue, E>,
) -> Result<ConstValue, E> {
self.into_const_with_mut(&mut f)
}
fn into_const_with_mut<E>(
self,
f: &mut impl FnMut(Name) -> Result<ConstValue, E>,
) -> Result<ConstValue, E> {
Ok(match self {
Self::Variable(name) => f(name)?,
Self::Null => ConstValue::Null,
Self::Number(num) => ConstValue::Number(num),
Self::String(s) => ConstValue::String(s),
Self::Boolean(b) => ConstValue::Boolean(b),
Self::Enum(v) => ConstValue::Enum(v),
Self::List(items) => ConstValue::List(
items
.into_iter()
.map(|value| value.into_const_with_mut(f))
.collect::<Result<_, _>>()?,
),
Self::Object(map) => ConstValue::Object(
map.into_iter()
.map(|(key, value)| Ok((key, value.into_const_with_mut(f)?)))
.collect::<Result<_, _>>()?,
),
})
}
/// Attempt to convert the value into a const value.
///
/// Will fail if the value contains variables.
#[must_use]
pub fn into_const(self) -> Option<ConstValue> {
self.into_const_with(|_| Err(())).ok()
}
/// Attempt to convert the value into JSON. This is equivalent to the `TryFrom` implementation.
///
/// # Errors
///
/// Fails if serialization fails (see enum docs for more info).
pub fn into_json(self) -> serde_json::Result<serde_json::Value> {
self.try_into()
}
/// Attempt to convert JSON into a value. This is equivalent to the `TryFrom` implementation.
///
/// # Errors
///
/// Fails if deserialization fails (see enum docs for more info).
pub fn from_json(json: serde_json::Value) -> serde_json::Result<Self> {
json.try_into()
}
}
impl Default for Value {
fn default() -> Self {
Self::Null
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Variable(name) => write!(f, "${}", name),
Self::Number(num) => write!(f, "{}", *num),
Self::String(val) => write_quoted(val, f),
Self::Boolean(true) => f.write_str("true"),
Self::Boolean(false) => f.write_str("false"),
Self::Null => f.write_str("null"),
Self::Enum(name) => f.write_str(name),
Self::List(items) => write_list(items, f),
Self::Object(map) => write_object(map, f),
}
}
}
impl From<ConstValue> for Value {
fn from(value: ConstValue) -> Self {
value.into_value()
}
}
impl TryFrom<serde_json::Value> for Value {
type Error = serde_json::Error;
fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
Self::deserialize(value)
}
}
impl TryFrom<Value> for serde_json::Value {
type Error = serde_json::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
serde_json::to_value(value)
}
}
fn fail_serialize_variable<S: Serializer>(_: &str, _: S) -> Result<S::Ok, S::Error> {
Err(S::Error::custom("cannot serialize variable"))
}
fn write_quoted(s: &str, f: &mut Formatter<'_>) -> fmt::Result {
f.write_char('"')?;
for c in s.chars() {
match c {
'\r' => f.write_str("\\r"),
'\n' => f.write_str("\\n"),
'\t' => f.write_str("\\t"),
'"' => f.write_str("\\\""),
'\\' => f.write_str("\\\\"),
c if c.is_control() => write!(f, "\\u{:04}", c as u32),
c => f.write_char(c),
}?
}
f.write_char('"')
}
fn write_list<T: Display>(list: impl IntoIterator<Item = T>, f: &mut Formatter<'_>) -> fmt::Result {
f.write_char('[')?;
for item in list {
item.fmt(f)?;
f.write_char(',')?;
}
f.write_char(']')
}
fn write_object<K: Display, V: Display>(
object: impl IntoIterator<Item = (K, V)>,
f: &mut Formatter<'_>,
) -> fmt::Result {
f.write_char('{')?;
for (name, value) in object {
write!(f, "{}: {},", name, value)?;
}
f.write_char('}')
}

563
value/src/ser.rs Normal file
View File

@ -0,0 +1,563 @@
use crate::{ConstValue, Name, Number};
use serde::ser::{self, Impossible};
use serde::Serialize;
use std::collections::BTreeMap;
use std::error::Error;
use std::fmt;
#[derive(Debug)]
pub enum SerializerError {
Custom(String),
}
impl fmt::Display for SerializerError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
SerializerError::Custom(ref s) => fmt.write_str(s),
}
}
}
impl Error for SerializerError {
fn description(&self) -> &str {
"ConstValue serializer error"
}
}
impl ser::Error for SerializerError {
fn custom<T: fmt::Display>(msg: T) -> SerializerError {
SerializerError::Custom(msg.to_string())
}
}
/// Convert a `T` into `ConstValue` which is an enum that can represent any valid GraphQL data.
pub fn to_value<T: ser::Serialize>(value: T) -> Result<ConstValue, SerializerError> {
value.serialize(Serializer)
}
struct Serializer;
impl ser::Serializer for Serializer {
type Ok = ConstValue;
type Error = SerializerError;
type SerializeSeq = SerializeSeq;
type SerializeTuple = SerializeTuple;
type SerializeTupleStruct = SerializeTupleStruct;
type SerializeTupleVariant = SerializeTupleVariant;
type SerializeMap = SerializeMap;
type SerializeStruct = SerializeStruct;
type SerializeStructVariant = SerializeStructVariant;
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Boolean(v))
}
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Number(v.into()))
}
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Number(v.into()))
}
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Number(v.into()))
}
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Number(v.into()))
}
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Number(v.into()))
}
fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Number(v.into()))
}
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Number(v.into()))
}
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Number(v.into()))
}
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
self.serialize_f64(v as f64)
}
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
match Number::from_f64(v) {
Some(v) => Ok(ConstValue::Number(v)),
None => Ok(ConstValue::Null),
}
}
fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
Err(SerializerError::Custom(
"char is not supported.".to_string(),
))
}
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::String(v.to_string()))
}
fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
Err(SerializerError::Custom(
"bytes is not supported.".to_string(),
))
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Null)
}
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: ser::Serialize,
{
value.serialize(self)
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Null)
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Null)
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::String(variant.to_string()))
}
fn serialize_newtype_struct<T: ?Sized>(
self,
_name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: ser::Serialize,
{
value.serialize(self)
}
fn serialize_newtype_variant<T: ?Sized>(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: ser::Serialize,
{
value.serialize(self).map(|v| {
let mut map = BTreeMap::new();
map.insert(Name::new(variant), v);
ConstValue::Object(map)
})
}
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Ok(SerializeSeq(vec![]))
}
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
Ok(SerializeTuple(vec![]))
}
fn serialize_tuple_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Ok(SerializeTupleStruct(vec![]))
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
Ok(SerializeTupleVariant(
Name::new(variant),
Vec::with_capacity(len),
))
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Ok(SerializeMap {
map: BTreeMap::new(),
key: None,
})
}
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Ok(SerializeStruct(BTreeMap::new()))
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
Ok(SerializeStructVariant(Name::new(variant), BTreeMap::new()))
}
}
struct SerializeSeq(Vec<ConstValue>);
impl ser::SerializeSeq for SerializeSeq {
type Ok = ConstValue;
type Error = SerializerError;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ser::Serialize,
{
let value = value.serialize(Serializer)?;
self.0.push(value);
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::List(self.0))
}
}
struct SerializeTuple(Vec<ConstValue>);
impl ser::SerializeTuple for SerializeTuple {
type Ok = ConstValue;
type Error = SerializerError;
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ser::Serialize,
{
let value = value.serialize(Serializer)?;
self.0.push(value);
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::List(self.0))
}
}
struct SerializeTupleStruct(Vec<ConstValue>);
impl ser::SerializeTupleStruct for SerializeTupleStruct {
type Ok = ConstValue;
type Error = SerializerError;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ser::Serialize,
{
let value = value.serialize(Serializer)?;
self.0.push(value);
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::List(self.0))
}
}
struct SerializeTupleVariant(Name, Vec<ConstValue>);
impl ser::SerializeTupleVariant for SerializeTupleVariant {
type Ok = ConstValue;
type Error = SerializerError;
fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ser::Serialize,
{
let value = value.serialize(Serializer)?;
self.1.push(value);
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
let mut map = BTreeMap::new();
map.insert(self.0, ConstValue::List(self.1));
Ok(ConstValue::Object(map))
}
}
struct SerializeMap {
map: BTreeMap<Name, ConstValue>,
key: Option<Name>,
}
impl ser::SerializeMap for SerializeMap {
type Ok = ConstValue;
type Error = SerializerError;
fn serialize_key<T: ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>
where
T: ser::Serialize,
{
let key = key.serialize(MapKeySerializer)?;
self.key = Some(key);
Ok(())
}
fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: ser::Serialize,
{
let value = value.serialize(Serializer)?;
self.map.insert(self.key.take().unwrap(), value);
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Object(self.map))
}
}
struct SerializeStruct(BTreeMap<Name, ConstValue>);
impl ser::SerializeStruct for SerializeStruct {
type Ok = ConstValue;
type Error = SerializerError;
fn serialize_field<T: ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Self::Error>
where
T: ser::Serialize,
{
let key = Name::new(key);
let value = value.serialize(Serializer)?;
self.0.insert(key, value);
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
Ok(ConstValue::Object(self.0))
}
}
struct SerializeStructVariant(Name, BTreeMap<Name, ConstValue>);
impl ser::SerializeStructVariant for SerializeStructVariant {
type Ok = ConstValue;
type Error = SerializerError;
fn serialize_field<T: ?Sized>(
&mut self,
key: &'static str,
value: &T,
) -> Result<(), Self::Error>
where
T: ser::Serialize,
{
let key = Name::new(key);
let value = value.serialize(Serializer)?;
self.1.insert(key, value);
Ok(())
}
fn end(self) -> Result<Self::Ok, Self::Error> {
let mut map = BTreeMap::new();
map.insert(self.0, ConstValue::Object(self.1));
Ok(ConstValue::Object(map))
}
}
fn key_must_be_a_string() -> SerializerError {
SerializerError::Custom("Key must be a string".to_string())
}
struct MapKeySerializer;
impl serde::Serializer for MapKeySerializer {
type Ok = Name;
type Error = SerializerError;
type SerializeSeq = Impossible<Name, SerializerError>;
type SerializeTuple = Impossible<Name, SerializerError>;
type SerializeTupleStruct = Impossible<Name, SerializerError>;
type SerializeTupleVariant = Impossible<Name, SerializerError>;
type SerializeMap = Impossible<Name, SerializerError>;
type SerializeStruct = Impossible<Name, SerializerError>;
type SerializeStructVariant = Impossible<Name, SerializerError>;
fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
Ok(Name::new(v))
}
fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error>
where
T: Serialize,
{
Err(key_must_be_a_string())
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_newtype_struct<T: ?Sized>(
self,
_name: &'static str,
_value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: Serialize,
{
Err(key_must_be_a_string())
}
fn serialize_newtype_variant<T: ?Sized>(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: Serialize,
{
Err(key_must_be_a_string())
}
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_tuple_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Err(key_must_be_a_string())
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
Err(key_must_be_a_string())
}
}