Add `parse_value` and `from_value` funcntions.
This commit is contained in:
parent
935cedc057
commit
e056edbaa0
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use super::*;
|
||||
use async_graphql_value::Name;
|
||||
|
||||
/// Parse a GraphQL query document.
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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"] }
|
|
@ -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)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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('}')
|
||||
}
|
|
@ -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())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue