#![doc = include_str!("../README.md")]
pub(crate) mod argument;
pub(crate) mod description;
pub(crate) mod directive;
pub(crate) mod document;
pub(crate) mod enum_;
pub(crate) mod field;
pub(crate) mod fragment;
pub(crate) mod input_object;
pub(crate) mod input_value;
pub(crate) mod interface;
pub(crate) mod name;
pub(crate) mod object;
pub(crate) mod operation;
pub(crate) mod scalar;
pub(crate) mod schema;
pub(crate) mod selection_set;
pub(crate) mod ty;
pub(crate) mod union;
pub(crate) mod variable;
use std::{collections::HashMap, fmt::Debug};
use arbitrary::Unstructured;
#[cfg(feature = "parser-impl")]
#[derive(Debug, Clone, thiserror::Error)]
pub enum FromError {
#[error("parse tree is missing a node")]
MissingNode,
#[error("invalid i32")]
ParseIntError(#[from] std::num::ParseIntError),
#[error("invalid f64")]
ParseFloatError(#[from] std::num::ParseFloatError),
#[error("invalid boolean")]
ParseBoolError(#[from] std::str::ParseBoolError),
}
pub use arbitrary::Result;
use argument::Argument;
pub use directive::DirectiveDef;
pub use document::Document;
pub use enum_::EnumTypeDef;
use field::FieldDef;
pub use fragment::FragmentDef;
pub use input_object::InputObjectTypeDef;
pub use interface::InterfaceTypeDef;
use name::Name;
pub use object::ObjectTypeDef;
pub use operation::OperationDef;
pub use scalar::ScalarTypeDef;
pub use schema::SchemaDef;
use ty::Ty;
pub use union::UnionTypeDef;
pub struct DocumentBuilder<'a> {
pub(crate) u: &'a mut Unstructured<'a>,
pub(crate) input_object_type_defs: Vec<InputObjectTypeDef>,
pub(crate) object_type_defs: Vec<ObjectTypeDef>,
pub(crate) interface_type_defs: Vec<InterfaceTypeDef>,
pub(crate) union_type_defs: Vec<UnionTypeDef>,
pub(crate) enum_type_defs: Vec<EnumTypeDef>,
pub(crate) scalar_type_defs: Vec<ScalarTypeDef>,
pub(crate) schema_def: Option<SchemaDef>,
pub(crate) directive_defs: Vec<DirectiveDef>,
pub(crate) operation_defs: Vec<OperationDef>,
pub(crate) fragment_defs: Vec<FragmentDef>,
pub(crate) stack: Vec<Box<dyn StackedEntity>>,
pub(crate) chosen_arguments: HashMap<Name, Vec<Argument>>,
pub(crate) chosen_aliases: HashMap<Name, Name>,
}
impl<'a> Debug for DocumentBuilder<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DocumentBuilder")
.field("input_object_type_defs", &self.input_object_type_defs)
.field("object_type_defs", &self.object_type_defs)
.field("interface_type_defs", &self.interface_type_defs)
.field("union_type_defs", &self.union_type_defs)
.field("enum_type_defs", &self.enum_type_defs)
.field("scalar_type_defs", &self.scalar_type_defs)
.field("schema_def", &self.schema_def)
.field("directive_defs", &self.directive_defs)
.field("operation_defs", &self.operation_defs)
.field("fragment_defs", &self.fragment_defs)
.finish()
}
}
impl<'a> DocumentBuilder<'a> {
pub fn new(u: &'a mut Unstructured<'a>) -> Result<Self> {
let mut builder = Self {
u,
object_type_defs: Vec::new(),
interface_type_defs: Vec::new(),
enum_type_defs: Vec::new(),
schema_def: None,
directive_defs: Vec::new(),
operation_defs: Vec::new(),
fragment_defs: Vec::new(),
scalar_type_defs: Vec::new(),
union_type_defs: Vec::new(),
input_object_type_defs: Vec::new(),
stack: Vec::new(),
chosen_arguments: HashMap::new(),
chosen_aliases: HashMap::new(),
};
for _ in 0..builder.u.int_in_range(1..=50)? {
let scalar_type_def = builder.scalar_type_definition()?;
builder.scalar_type_defs.push(scalar_type_def);
}
for _ in 0..builder.u.int_in_range(1..=50)? {
let enum_type_def = builder.enum_type_definition()?;
builder.enum_type_defs.push(enum_type_def);
}
for _ in 0..builder.u.int_in_range(1..=50)? {
let interface_type_def = builder.interface_type_definition()?;
builder.interface_type_defs.push(interface_type_def);
}
for _ in 0..builder.u.int_in_range(1..=50)? {
let object_type_def = builder.object_type_definition()?;
builder.object_type_defs.push(object_type_def);
}
for _ in 0..builder.u.int_in_range(1..=50)? {
let union_type_def = builder.union_type_definition()?;
builder.union_type_defs.push(union_type_def);
}
for _ in 0..builder.u.int_in_range(1..=50)? {
let input_object_type_def = builder.input_object_type_definition()?;
builder.input_object_type_defs.push(input_object_type_def);
}
for _ in 0..builder.u.int_in_range(1..=50)? {
let fragment_def = builder.fragment_definition()?;
builder.fragment_defs.push(fragment_def);
}
for _ in 0..builder.u.int_in_range(1..=50)? {
let directive_def = builder.directive_def()?;
builder.directive_defs.push(directive_def);
}
let schema_def = builder.schema_definition()?;
builder.schema_def = Some(schema_def);
for _ in 0..builder.u.int_in_range(1..=50)? {
let operation_def = builder.operation_definition()?;
if let Some(operation_def) = operation_def {
builder.operation_defs.push(operation_def);
}
}
Ok(builder)
}
pub fn with_document(u: &'a mut Unstructured<'a>, document: Document) -> Result<Self> {
let builder = Self {
u,
object_type_defs: document.object_type_definitions,
interface_type_defs: document.interface_type_definitions,
enum_type_defs: document.enum_type_definitions,
schema_def: document.schema_definition,
directive_defs: document.directive_definitions,
operation_defs: document.operation_definitions,
fragment_defs: document.fragment_definitions,
scalar_type_defs: document.scalar_type_definitions,
union_type_defs: document.union_type_definitions,
input_object_type_defs: document.input_object_type_definitions,
stack: Vec::new(),
chosen_arguments: HashMap::new(),
chosen_aliases: HashMap::new(),
};
Ok(builder)
}
pub fn input_exhausted(&self) -> bool {
self.u.is_empty()
}
pub fn finish(self) -> Document {
Document {
schema_definition: self.schema_def,
object_type_definitions: self.object_type_defs,
interface_type_definitions: self.interface_type_defs,
enum_type_definitions: self.enum_type_defs,
directive_definitions: self.directive_defs,
operation_definitions: self.operation_defs,
fragment_definitions: self.fragment_defs,
scalar_type_definitions: self.scalar_type_defs,
union_type_definitions: self.union_type_defs,
input_object_type_definitions: self.input_object_type_defs,
}
}
pub(crate) fn stack_ty(&mut self, ty: &Ty) -> bool {
if ty.is_builtin() {
return false;
}
let type_name = ty.name();
if let Some(object_ty) = self
.object_type_defs
.iter()
.find(|object_ty_def| &object_ty_def.name == type_name)
.cloned()
{
self.stack.push(Box::new(object_ty));
true
} else if let Some(itf_type) = self
.interface_type_defs
.iter()
.find(|itf_type_def| &itf_type_def.name == type_name)
.cloned()
{
self.stack.push(Box::new(itf_type));
true
} else if let Some(_enum_ty) = self
.enum_type_defs
.iter()
.find(|object_ty_def| &object_ty_def.name == type_name)
.cloned()
{
false
} else {
todo!("'{:?}' need to implement for union, scalar, ...", type_name);
}
}
}
pub(crate) trait StackedEntity {
fn name(&self) -> &Name;
fn fields_def(&self) -> &[FieldDef];
}