juniper/types/
containers.rs

1use std::{
2    mem::{self, MaybeUninit},
3    ptr,
4};
5
6use crate::{
7    ast::{FromInputValue, InputValue, Selection, ToInputValue},
8    executor::{ExecutionResult, Executor, FieldError, IntoFieldError, Registry},
9    schema::meta::MetaType,
10    types::{
11        async_await::GraphQLValueAsync,
12        base::{GraphQLType, GraphQLValue},
13    },
14    value::{ScalarValue, Value},
15};
16
17impl<S, T> GraphQLType<S> for Option<T>
18where
19    T: GraphQLType<S>,
20    S: ScalarValue,
21{
22    fn name(_: &Self::TypeInfo) -> Option<&'static str> {
23        None
24    }
25
26    fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
27    where
28        S: 'r,
29    {
30        registry.build_nullable_type::<T>(info).into_meta()
31    }
32}
33
34impl<S, T> GraphQLValue<S> for Option<T>
35where
36    S: ScalarValue,
37    T: GraphQLValue<S>,
38{
39    type Context = T::Context;
40    type TypeInfo = T::TypeInfo;
41
42    fn type_name(&self, _: &Self::TypeInfo) -> Option<&'static str> {
43        None
44    }
45
46    fn resolve(
47        &self,
48        info: &Self::TypeInfo,
49        _: Option<&[Selection<S>]>,
50        executor: &Executor<Self::Context, S>,
51    ) -> ExecutionResult<S> {
52        match *self {
53            Some(ref obj) => executor.resolve(info, obj),
54            None => Ok(Value::null()),
55        }
56    }
57}
58
59impl<S, T> GraphQLValueAsync<S> for Option<T>
60where
61    T: GraphQLValueAsync<S>,
62    T::TypeInfo: Sync,
63    T::Context: Sync,
64    S: ScalarValue + Send + Sync,
65{
66    fn resolve_async<'a>(
67        &'a self,
68        info: &'a Self::TypeInfo,
69        _: Option<&'a [Selection<S>]>,
70        executor: &'a Executor<Self::Context, S>,
71    ) -> crate::BoxFuture<'a, ExecutionResult<S>> {
72        let f = async move {
73            let value = match self {
74                Some(obj) => executor.resolve_into_value_async(info, obj).await,
75                None => Value::null(),
76            };
77            Ok(value)
78        };
79        Box::pin(f)
80    }
81}
82
83impl<S, T: FromInputValue<S>> FromInputValue<S> for Option<T> {
84    type Error = T::Error;
85
86    fn from_input_value(v: &InputValue<S>) -> Result<Self, Self::Error> {
87        match v {
88            InputValue::Null => Ok(None),
89            v => v.convert().map(Some),
90        }
91    }
92}
93
94impl<S, T: ToInputValue<S>> ToInputValue<S> for Option<T> {
95    fn to_input_value(&self) -> InputValue<S> {
96        match self {
97            Some(v) => v.to_input_value(),
98            None => InputValue::Null,
99        }
100    }
101}
102
103impl<S, T> GraphQLType<S> for Vec<T>
104where
105    T: GraphQLType<S>,
106    S: ScalarValue,
107{
108    fn name(_: &Self::TypeInfo) -> Option<&'static str> {
109        None
110    }
111
112    fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
113    where
114        S: 'r,
115    {
116        registry.build_list_type::<T>(info, None).into_meta()
117    }
118}
119
120impl<S, T> GraphQLValue<S> for Vec<T>
121where
122    T: GraphQLValue<S>,
123    S: ScalarValue,
124{
125    type Context = T::Context;
126    type TypeInfo = T::TypeInfo;
127
128    fn type_name(&self, _: &Self::TypeInfo) -> Option<&'static str> {
129        None
130    }
131
132    fn resolve(
133        &self,
134        info: &Self::TypeInfo,
135        _: Option<&[Selection<S>]>,
136        executor: &Executor<Self::Context, S>,
137    ) -> ExecutionResult<S> {
138        resolve_into_list(executor, info, self.iter())
139    }
140}
141
142impl<S, T> GraphQLValueAsync<S> for Vec<T>
143where
144    T: GraphQLValueAsync<S>,
145    T::TypeInfo: Sync,
146    T::Context: Sync,
147    S: ScalarValue + Send + Sync,
148{
149    fn resolve_async<'a>(
150        &'a self,
151        info: &'a Self::TypeInfo,
152        _: Option<&'a [Selection<S>]>,
153        executor: &'a Executor<Self::Context, S>,
154    ) -> crate::BoxFuture<'a, ExecutionResult<S>> {
155        let f = resolve_into_list_async(executor, info, self.iter());
156        Box::pin(f)
157    }
158}
159
160impl<S: ScalarValue, T: FromInputValue<S>> FromInputValue<S> for Vec<T> {
161    type Error = FromInputValueVecError<T, S>;
162
163    fn from_input_value(v: &InputValue<S>) -> Result<Self, Self::Error> {
164        match v {
165            InputValue::List(l) => l
166                .iter()
167                .map(|i| i.item.convert().map_err(FromInputValueVecError::Item))
168                .collect(),
169            // See "Input Coercion" on List types:
170            // https://spec.graphql.org/October2021#sec-Combining-List-and-Non-Null
171            InputValue::Null => Err(FromInputValueVecError::Null),
172            other => other
173                .convert()
174                .map(|e| vec![e])
175                .map_err(FromInputValueVecError::Item),
176        }
177    }
178}
179
180impl<T, S> ToInputValue<S> for Vec<T>
181where
182    T: ToInputValue<S>,
183    S: ScalarValue,
184{
185    fn to_input_value(&self) -> InputValue<S> {
186        InputValue::list(self.iter().map(T::to_input_value).collect())
187    }
188}
189
190/// Possible errors of converting [`InputValue`] into [`Vec`].
191#[derive(Clone, Debug, Eq, PartialEq)]
192pub enum FromInputValueVecError<T, S>
193where
194    T: FromInputValue<S>,
195    S: ScalarValue,
196{
197    /// [`InputValue`] cannot be [`Null`].
198    ///
199    /// See ["Combining List and Non-Null" section of spec][1].
200    ///
201    /// [`Null`]: [`InputValue::Null`]
202    /// [1]: https://spec.graphql.org/October2021#sec-Combining-List-and-Non-Null
203    Null,
204
205    /// Error of converting [`InputValue::List`]'s item.
206    Item(T::Error),
207}
208
209impl<T, S> IntoFieldError<S> for FromInputValueVecError<T, S>
210where
211    T: FromInputValue<S>,
212    T::Error: IntoFieldError<S>,
213    S: ScalarValue,
214{
215    fn into_field_error(self) -> FieldError<S> {
216        match self {
217            Self::Null => "Failed to convert into `Vec`: Value cannot be `null`".into(),
218            Self::Item(s) => s.into_field_error(),
219        }
220    }
221}
222
223impl<S, T> GraphQLType<S> for [T]
224where
225    S: ScalarValue,
226    T: GraphQLType<S>,
227{
228    fn name(_: &Self::TypeInfo) -> Option<&'static str> {
229        None
230    }
231
232    fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
233    where
234        S: 'r,
235    {
236        registry.build_list_type::<T>(info, None).into_meta()
237    }
238}
239
240impl<S, T> GraphQLValue<S> for [T]
241where
242    S: ScalarValue,
243    T: GraphQLValue<S>,
244{
245    type Context = T::Context;
246    type TypeInfo = T::TypeInfo;
247
248    fn type_name(&self, _: &Self::TypeInfo) -> Option<&'static str> {
249        None
250    }
251
252    fn resolve(
253        &self,
254        info: &Self::TypeInfo,
255        _: Option<&[Selection<S>]>,
256        executor: &Executor<Self::Context, S>,
257    ) -> ExecutionResult<S> {
258        resolve_into_list(executor, info, self.iter())
259    }
260}
261
262impl<S, T> GraphQLValueAsync<S> for [T]
263where
264    T: GraphQLValueAsync<S>,
265    T::TypeInfo: Sync,
266    T::Context: Sync,
267    S: ScalarValue + Send + Sync,
268{
269    fn resolve_async<'a>(
270        &'a self,
271        info: &'a Self::TypeInfo,
272        _: Option<&'a [Selection<S>]>,
273        executor: &'a Executor<Self::Context, S>,
274    ) -> crate::BoxFuture<'a, ExecutionResult<S>> {
275        let f = resolve_into_list_async(executor, info, self.iter());
276        Box::pin(f)
277    }
278}
279
280impl<'a, T, S> ToInputValue<S> for &'a [T]
281where
282    T: ToInputValue<S>,
283    S: ScalarValue,
284{
285    fn to_input_value(&self) -> InputValue<S> {
286        InputValue::list(self.iter().map(T::to_input_value).collect())
287    }
288}
289
290impl<S, T, const N: usize> GraphQLType<S> for [T; N]
291where
292    S: ScalarValue,
293    T: GraphQLType<S>,
294{
295    fn name(_: &Self::TypeInfo) -> Option<&'static str> {
296        None
297    }
298
299    fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
300    where
301        S: 'r,
302    {
303        registry.build_list_type::<T>(info, Some(N)).into_meta()
304    }
305}
306
307impl<S, T, const N: usize> GraphQLValue<S> for [T; N]
308where
309    S: ScalarValue,
310    T: GraphQLValue<S>,
311{
312    type Context = T::Context;
313    type TypeInfo = T::TypeInfo;
314
315    fn type_name(&self, _: &Self::TypeInfo) -> Option<&'static str> {
316        None
317    }
318
319    fn resolve(
320        &self,
321        info: &Self::TypeInfo,
322        _: Option<&[Selection<S>]>,
323        executor: &Executor<Self::Context, S>,
324    ) -> ExecutionResult<S> {
325        resolve_into_list(executor, info, self.iter())
326    }
327}
328
329impl<S, T, const N: usize> GraphQLValueAsync<S> for [T; N]
330where
331    T: GraphQLValueAsync<S>,
332    T::TypeInfo: Sync,
333    T::Context: Sync,
334    S: ScalarValue + Send + Sync,
335{
336    fn resolve_async<'a>(
337        &'a self,
338        info: &'a Self::TypeInfo,
339        _: Option<&'a [Selection<S>]>,
340        executor: &'a Executor<Self::Context, S>,
341    ) -> crate::BoxFuture<'a, ExecutionResult<S>> {
342        let f = resolve_into_list_async(executor, info, self.iter());
343        Box::pin(f)
344    }
345}
346
347impl<T, S, const N: usize> FromInputValue<S> for [T; N]
348where
349    T: FromInputValue<S>,
350    S: ScalarValue,
351{
352    type Error = FromInputValueArrayError<T, S>;
353
354    fn from_input_value(v: &InputValue<S>) -> Result<Self, Self::Error> {
355        struct PartiallyInitializedArray<T, const N: usize> {
356            arr: [MaybeUninit<T>; N],
357            init_len: usize,
358            no_drop: bool,
359        }
360
361        impl<T, const N: usize> Drop for PartiallyInitializedArray<T, N> {
362            fn drop(&mut self) {
363                if self.no_drop {
364                    return;
365                }
366                // Dropping a `MaybeUninit` does nothing, thus we need to drop
367                // the initialized elements manually, otherwise we may introduce
368                // a memory/resource leak if `T: Drop`.
369                for elem in &mut self.arr[0..self.init_len] {
370                    // SAFETY: This is safe, because `self.init_len` represents
371                    //         exactly the number of initialized elements.
372                    unsafe {
373                        ptr::drop_in_place(elem.as_mut_ptr());
374                    }
375                }
376            }
377        }
378
379        match *v {
380            InputValue::List(ref ls) => {
381                if ls.len() != N {
382                    return Err(FromInputValueArrayError::WrongCount {
383                        actual: ls.len(),
384                        expected: N,
385                    });
386                }
387                if N == 0 {
388                    // TODO: Use `mem::transmute` instead of
389                    //       `mem::transmute_copy` below, once it's allowed
390                    //       for const generics:
391                    //       https://github.com/rust-lang/rust/issues/61956
392                    // SAFETY: `mem::transmute_copy` is safe here, because we
393                    //         check `N` to be `0`. It's no-op, actually.
394                    return Ok(unsafe { mem::transmute_copy::<[T; 0], Self>(&[]) });
395                }
396
397                // SAFETY: The reason we're using a wrapper struct implementing
398                //         `Drop` here is to be panic safe:
399                //         `T: FromInputValue<S>` implementation is not
400                //         controlled by us, so calling `i.item.convert()` below
401                //         may cause a panic when our array is initialized only
402                //         partially. In such situation we need to drop already
403                //         initialized values to avoid possible memory/resource
404                //         leaks if `T: Drop`.
405                let mut out = PartiallyInitializedArray::<T, N> {
406                    // SAFETY: The `.assume_init()` here is safe, because the
407                    //         type we are claiming to have initialized here is
408                    //         a bunch of `MaybeUninit`s, which do not require
409                    //         any initialization.
410                    arr: unsafe { MaybeUninit::uninit().assume_init() },
411                    init_len: 0,
412                    no_drop: false,
413                };
414
415                let mut items = ls.iter().map(|i| i.item.convert());
416                for elem in &mut out.arr[..] {
417                    if let Some(i) = items
418                        .next()
419                        .transpose()
420                        .map_err(FromInputValueArrayError::Item)?
421                    {
422                        *elem = MaybeUninit::new(i);
423                        out.init_len += 1;
424                    }
425                }
426
427                // Do not drop collected `items`, because we're going to return
428                // them.
429                out.no_drop = true;
430
431                // TODO: Use `mem::transmute` instead of `mem::transmute_copy`
432                //       below, once it's allowed for const generics:
433                //       https://github.com/rust-lang/rust/issues/61956
434                // SAFETY: `mem::transmute_copy` is safe here, because we have
435                //         exactly `N` initialized `items`.
436                //         Also, despite `mem::transmute_copy` copies the value,
437                //         we won't have a double-free when `T: Drop` here,
438                //         because original array elements are `MaybeUninit`, so
439                //         do nothing on `Drop`.
440                Ok(unsafe { mem::transmute_copy::<_, Self>(&out.arr) })
441            }
442            // See "Input Coercion" on List types:
443            // https://spec.graphql.org/October2021#sec-Combining-List-and-Non-Null
444            InputValue::Null => Err(FromInputValueArrayError::Null),
445            ref other => {
446                other
447                    .convert()
448                    .map_err(FromInputValueArrayError::Item)
449                    .and_then(|e: T| {
450                        // TODO: Use `mem::transmute` instead of
451                        //       `mem::transmute_copy` below, once it's allowed
452                        //       for const generics:
453                        //       https://github.com/rust-lang/rust/issues/61956
454                        if N == 1 {
455                            // SAFETY: `mem::transmute_copy` is safe here,
456                            //         because we check `N` to be `1`.
457                            //         Also, despite `mem::transmute_copy`
458                            //         copies the value, we won't have a
459                            //         double-free when `T: Drop` here, because
460                            //         original `e: T` value is wrapped into
461                            //         `mem::ManuallyDrop`, so does nothing on
462                            //         `Drop`.
463                            Ok(unsafe {
464                                mem::transmute_copy::<_, Self>(&[mem::ManuallyDrop::new(e)])
465                            })
466                        } else {
467                            Err(FromInputValueArrayError::WrongCount {
468                                actual: 1,
469                                expected: N,
470                            })
471                        }
472                    })
473            }
474        }
475    }
476}
477
478impl<T, S, const N: usize> ToInputValue<S> for [T; N]
479where
480    T: ToInputValue<S>,
481    S: ScalarValue,
482{
483    fn to_input_value(&self) -> InputValue<S> {
484        InputValue::list(self.iter().map(T::to_input_value).collect())
485    }
486}
487
488/// Error converting [`InputValue`] into exact-size [`array`](prim@array).
489#[derive(Clone, Debug, Eq, PartialEq)]
490pub enum FromInputValueArrayError<T, S>
491where
492    T: FromInputValue<S>,
493    S: ScalarValue,
494{
495    /// [`InputValue`] cannot be [`Null`].
496    ///
497    /// See ["Combining List and Non-Null" section of spec][1].
498    ///
499    /// [`Null`]: [`InputValue::Null`]
500    /// [1]: https://spec.graphql.org/October2021#sec-Combining-List-and-Non-Null
501    Null,
502
503    /// Wrong count of items.
504    WrongCount {
505        /// Actual count of items.
506        actual: usize,
507
508        /// Expected count of items.
509        expected: usize,
510    },
511
512    /// Error of converting [`InputValue::List`]'s item.
513    Item(T::Error),
514}
515
516impl<T, S> IntoFieldError<S> for FromInputValueArrayError<T, S>
517where
518    T: FromInputValue<S>,
519    T::Error: IntoFieldError<S>,
520    S: ScalarValue,
521{
522    fn into_field_error(self) -> FieldError<S> {
523        const ERROR_PREFIX: &str = "Failed to convert into exact-size array";
524        match self {
525            Self::Null => format!("{ERROR_PREFIX}: Value cannot be `null`").into(),
526            Self::WrongCount { actual, expected } => {
527                format!("{ERROR_PREFIX}: wrong elements count: {actual} instead of {expected}",)
528                    .into()
529            }
530            Self::Item(s) => s.into_field_error(),
531        }
532    }
533}
534
535fn resolve_into_list<'t, S, T, I>(
536    executor: &Executor<T::Context, S>,
537    info: &T::TypeInfo,
538    iter: I,
539) -> ExecutionResult<S>
540where
541    S: ScalarValue,
542    I: Iterator<Item = &'t T> + ExactSizeIterator,
543    T: GraphQLValue<S> + ?Sized + 't,
544{
545    let stop_on_null = executor
546        .current_type()
547        .list_contents()
548        .expect("Current type is not a list type")
549        .is_non_null();
550    let mut result = Vec::with_capacity(iter.len());
551
552    for o in iter {
553        let val = executor.resolve(info, o)?;
554        if stop_on_null && val.is_null() {
555            return Ok(val);
556        } else {
557            result.push(val)
558        }
559    }
560
561    Ok(Value::list(result))
562}
563
564async fn resolve_into_list_async<'a, 't, S, T, I>(
565    executor: &'a Executor<'a, 'a, T::Context, S>,
566    info: &'a T::TypeInfo,
567    items: I,
568) -> ExecutionResult<S>
569where
570    I: Iterator<Item = &'t T> + ExactSizeIterator,
571    T: GraphQLValueAsync<S> + ?Sized + 't,
572    T::TypeInfo: Sync,
573    T::Context: Sync,
574    S: ScalarValue + Send + Sync,
575{
576    use futures::stream::{FuturesOrdered, StreamExt as _};
577
578    let stop_on_null = executor
579        .current_type()
580        .list_contents()
581        .expect("Current type is not a list type")
582        .is_non_null();
583
584    let mut futures = items
585        .map(|it| async move { executor.resolve_into_value_async(info, it).await })
586        .collect::<FuturesOrdered<_>>();
587
588    let mut values = Vec::with_capacity(futures.len());
589    while let Some(value) = futures.next().await {
590        if stop_on_null && value.is_null() {
591            return Ok(value);
592        }
593        values.push(value);
594    }
595
596    Ok(Value::list(values))
597}
598
599#[cfg(test)]
600mod coercion {
601    use crate::{graphql_input_value, FromInputValue as _, InputValue, IntoFieldError as _};
602
603    use super::{FromInputValueArrayError, FromInputValueVecError};
604
605    type V = InputValue;
606
607    #[test]
608    fn option() {
609        let v: V = graphql_input_value!(null);
610        assert_eq!(<Option<i32>>::from_input_value(&v), Ok(None));
611
612        let v: V = graphql_input_value!(1);
613        assert_eq!(<Option<i32>>::from_input_value(&v), Ok(Some(1)));
614    }
615
616    // See "Input Coercion" examples on List types:
617    // https://spec.graphql.org/October2021/#sec-List.Input-Coercion
618    #[test]
619    fn vec() {
620        let v: V = graphql_input_value!(null);
621        assert_eq!(
622            <Vec<i32>>::from_input_value(&v),
623            Err(FromInputValueVecError::Null),
624        );
625        assert_eq!(
626            <Vec<Option<i32>>>::from_input_value(&v),
627            Err(FromInputValueVecError::Null),
628        );
629        assert_eq!(<Option<Vec<i32>>>::from_input_value(&v), Ok(None));
630        assert_eq!(<Option<Vec<Option<i32>>>>::from_input_value(&v), Ok(None));
631        assert_eq!(
632            <Vec<Vec<i32>>>::from_input_value(&v),
633            Err(FromInputValueVecError::Null),
634        );
635        assert_eq!(
636            <Option<Vec<Option<Vec<Option<i32>>>>>>::from_input_value(&v),
637            Ok(None),
638        );
639
640        let v: V = graphql_input_value!(1);
641        assert_eq!(<Vec<i32>>::from_input_value(&v), Ok(vec![1]));
642        assert_eq!(<Vec<Option<i32>>>::from_input_value(&v), Ok(vec![Some(1)]));
643        assert_eq!(<Option<Vec<i32>>>::from_input_value(&v), Ok(Some(vec![1])));
644        assert_eq!(
645            <Option<Vec<Option<i32>>>>::from_input_value(&v),
646            Ok(Some(vec![Some(1)])),
647        );
648        assert_eq!(<Vec<Vec<i32>>>::from_input_value(&v), Ok(vec![vec![1]]));
649        assert_eq!(
650            <Option<Vec<Option<Vec<Option<i32>>>>>>::from_input_value(&v),
651            Ok(Some(vec![Some(vec![Some(1)])])),
652        );
653
654        let v: V = graphql_input_value!([1, 2, 3]);
655        assert_eq!(<Vec<i32>>::from_input_value(&v), Ok(vec![1, 2, 3]));
656        assert_eq!(
657            <Option<Vec<i32>>>::from_input_value(&v),
658            Ok(Some(vec![1, 2, 3])),
659        );
660        assert_eq!(
661            <Vec<Option<i32>>>::from_input_value(&v),
662            Ok(vec![Some(1), Some(2), Some(3)]),
663        );
664        assert_eq!(
665            <Option<Vec<Option<i32>>>>::from_input_value(&v),
666            Ok(Some(vec![Some(1), Some(2), Some(3)])),
667        );
668        assert_eq!(
669            <Vec<Vec<i32>>>::from_input_value(&v),
670            Ok(vec![vec![1], vec![2], vec![3]]),
671        );
672        // Looks like the spec ambiguity.
673        // See: https://github.com/graphql/graphql-spec/pull/515
674        assert_eq!(
675            <Option<Vec<Option<Vec<Option<i32>>>>>>::from_input_value(&v),
676            Ok(Some(vec![
677                Some(vec![Some(1)]),
678                Some(vec![Some(2)]),
679                Some(vec![Some(3)]),
680            ])),
681        );
682
683        let v: V = graphql_input_value!([1, 2, null]);
684        assert_eq!(
685            <Vec<i32>>::from_input_value(&v),
686            Err(FromInputValueVecError::Item(
687                "Expected `Int`, found: null".into_field_error(),
688            )),
689        );
690        assert_eq!(
691            <Option<Vec<i32>>>::from_input_value(&v),
692            Err(FromInputValueVecError::Item(
693                "Expected `Int`, found: null".into_field_error(),
694            )),
695        );
696        assert_eq!(
697            <Vec<Option<i32>>>::from_input_value(&v),
698            Ok(vec![Some(1), Some(2), None]),
699        );
700        assert_eq!(
701            <Option<Vec<Option<i32>>>>::from_input_value(&v),
702            Ok(Some(vec![Some(1), Some(2), None])),
703        );
704        assert_eq!(
705            <Vec<Vec<i32>>>::from_input_value(&v),
706            Err(FromInputValueVecError::Item(FromInputValueVecError::Null)),
707        );
708        // Looks like the spec ambiguity.
709        // See: https://github.com/graphql/graphql-spec/pull/515
710        assert_eq!(
711            <Option<Vec<Option<Vec<Option<i32>>>>>>::from_input_value(&v),
712            Ok(Some(vec![Some(vec![Some(1)]), Some(vec![Some(2)]), None])),
713        );
714    }
715
716    // See "Input Coercion" examples on List types:
717    // https://spec.graphql.org/October2021#sec-List.Input-Coercion
718    #[test]
719    fn array() {
720        let v: V = graphql_input_value!(null);
721        assert_eq!(
722            <[i32; 0]>::from_input_value(&v),
723            Err(FromInputValueArrayError::Null),
724        );
725        assert_eq!(
726            <[i32; 1]>::from_input_value(&v),
727            Err(FromInputValueArrayError::Null),
728        );
729        assert_eq!(
730            <[Option<i32>; 0]>::from_input_value(&v),
731            Err(FromInputValueArrayError::Null),
732        );
733        assert_eq!(
734            <[Option<i32>; 1]>::from_input_value(&v),
735            Err(FromInputValueArrayError::Null),
736        );
737        assert_eq!(<Option<[i32; 0]>>::from_input_value(&v), Ok(None));
738        assert_eq!(<Option<[i32; 1]>>::from_input_value(&v), Ok(None));
739        assert_eq!(<Option<[Option<i32>; 0]>>::from_input_value(&v), Ok(None));
740        assert_eq!(<Option<[Option<i32>; 1]>>::from_input_value(&v), Ok(None));
741        assert_eq!(
742            <[[i32; 1]; 1]>::from_input_value(&v),
743            Err(FromInputValueArrayError::Null),
744        );
745        assert_eq!(
746            <Option<[Option<[Option<i32>; 1]>; 1]>>::from_input_value(&v),
747            Ok(None),
748        );
749
750        let v: V = graphql_input_value!(1);
751        assert_eq!(<[i32; 1]>::from_input_value(&v), Ok([1]));
752        assert_eq!(
753            <[i32; 0]>::from_input_value(&v),
754            Err(FromInputValueArrayError::WrongCount {
755                expected: 0,
756                actual: 1,
757            }),
758        );
759        assert_eq!(<[Option<i32>; 1]>::from_input_value(&v), Ok([Some(1)]));
760        assert_eq!(<Option<[i32; 1]>>::from_input_value(&v), Ok(Some([1])));
761        assert_eq!(
762            <Option<[Option<i32>; 1]>>::from_input_value(&v),
763            Ok(Some([Some(1)])),
764        );
765        assert_eq!(<[[i32; 1]; 1]>::from_input_value(&v), Ok([[1]]));
766        assert_eq!(
767            <Option<[Option<[Option<i32>; 1]>; 1]>>::from_input_value(&v),
768            Ok(Some([Some([Some(1)])])),
769        );
770
771        let v: V = graphql_input_value!([1, 2, 3]);
772        assert_eq!(<[i32; 3]>::from_input_value(&v), Ok([1, 2, 3]));
773        assert_eq!(
774            <Option<[i32; 3]>>::from_input_value(&v),
775            Ok(Some([1, 2, 3])),
776        );
777        assert_eq!(
778            <[Option<i32>; 3]>::from_input_value(&v),
779            Ok([Some(1), Some(2), Some(3)]),
780        );
781        assert_eq!(
782            <Option<[Option<i32>; 3]>>::from_input_value(&v),
783            Ok(Some([Some(1), Some(2), Some(3)])),
784        );
785        assert_eq!(<[[i32; 1]; 3]>::from_input_value(&v), Ok([[1], [2], [3]]));
786        // Looks like the spec ambiguity.
787        // See: https://github.com/graphql/graphql-spec/pull/515
788        assert_eq!(
789            <Option<[Option<[Option<i32>; 1]>; 3]>>::from_input_value(&v),
790            Ok(Some([Some([Some(1)]), Some([Some(2)]), Some([Some(3)]),])),
791        );
792
793        let v: V = graphql_input_value!([1, 2, null]);
794        assert_eq!(
795            <[i32; 3]>::from_input_value(&v),
796            Err(FromInputValueArrayError::Item(
797                "Expected `Int`, found: null".into_field_error(),
798            )),
799        );
800        assert_eq!(
801            <Option<[i32; 3]>>::from_input_value(&v),
802            Err(FromInputValueArrayError::Item(
803                "Expected `Int`, found: null".into_field_error(),
804            )),
805        );
806        assert_eq!(
807            <[Option<i32>; 3]>::from_input_value(&v),
808            Ok([Some(1), Some(2), None]),
809        );
810        assert_eq!(
811            <Option<[Option<i32>; 3]>>::from_input_value(&v),
812            Ok(Some([Some(1), Some(2), None])),
813        );
814        assert_eq!(
815            <[[i32; 1]; 3]>::from_input_value(&v),
816            Err(FromInputValueArrayError::Item(
817                FromInputValueArrayError::Null
818            )),
819        );
820        // Looks like the spec ambiguity.
821        // See: https://github.com/graphql/graphql-spec/pull/515
822        assert_eq!(
823            <Option<[Option<[Option<i32>; 1]>; 3]>>::from_input_value(&v),
824            Ok(Some([Some([Some(1)]), Some([Some(2)]), None])),
825        );
826    }
827}