itemsVal
    :: forall err schema.
       (schema -> Value -> [err])
    -> Items schema
    -> Vector Value
    -> (Maybe (ItemsInvalid err), [(JP.Index, Value)])
       -- ^ The second item in the tuple is the elements of the original
       -- JSON Array still remaining to be checked by @"additionalItems"@.
itemsVal f a xs =
    case a of
        ItemsObject subSchema ->
            case NE.nonEmpty (mapMaybe (validateElem subSchema) indexed) of
                Nothing   -> (Nothing, mempty)
                Just errs -> (Just (ItemsObjectInvalid errs), mempty)
        ItemsArray subSchemas ->
            let remaining = drop (length subSchemas) indexed
                res = catMaybes (zipWith validateElem subSchemas indexed)
            in case NE.nonEmpty res of
                Nothing   -> (Nothing, remaining)
                Just errs -> (Just (ItemsArrayInvalid errs), remaining)
  where
    indexed :: [(JP.Index, Value)]
    indexed = zip (JP.Index <$> [0..]) (V.toList xs)

    validateElem
        :: schema
        -> (JP.Index, Value)
        -> Maybe (JP.Index, NonEmpty err)
    validateElem schema (index,x) =
        (\v -> (index, v)) <$> NE.nonEmpty (f schema x)

--------------------------------------------------
-- * additionalItems
--------------------------------------------------
itemsVal
    :: forall err schema.
       (schema -> Value -> [err])
    -> Items schema
    -> Vector Value
    -> (Maybe (ItemsInvalid err), [(JP.Index, Value)])
itemsVal f a xs =
    case a of
        ItemsObject subSchema ->
            case NE.nonEmpty (mapMaybe (validateElem subSchema) indexed) of
                Nothing   -> (Nothing, mempty)
                Just errs -> (Just (ItemsObjectInvalid errs), mempty)
        ItemsArray subSchemas ->
            let remaining = drop (length subSchemas) indexed
                res = catMaybes (zipWith validateElem subSchemas indexed)
            in case NE.nonEmpty res of
                Nothing   -> (Nothing, remaining)
                Just errs -> (Just (ItemsArrayInvalid errs), remaining)
  where
    indexed :: [(JP.Index, Value)]
    indexed = zip (JP.Index <$> [0..]) (V.toList xs)

    validateElem
        :: schema
        -> (JP.Index, Value)
        -> Maybe (JP.Index, NonEmpty err)
    validateElem schema (index,x) =
        (\v -> (index, v)) <$> NE.nonEmpty (f schema x)

--------------------------------------------------
-- * additionalItems
--------------------------------------------------
itemsVal f a xs =
    case a of
        ItemsObject subSchema ->
            case NE.nonEmpty (mapMaybe (validateElem subSchema) indexed) of
                Nothing   -> (Nothing, mempty)
                Just errs -> (Just (ItemsObjectInvalid errs), mempty)
        ItemsArray subSchemas ->
            let remaining = drop (length subSchemas) indexed
                res = catMaybes (zipWith validateElem subSchemas indexed)
            in case NE.nonEmpty res of
                Nothing   -> (Nothing, remaining)
                Just errs -> (Just (ItemsArrayInvalid errs), remaining)
  where
    indexed :: [(JP.Index, Value)]
    indexed = zip (JP.Index <$> [0..]) (V.toList xs)

    validateElem
        :: schema
        -> (JP.Index, Value)
        -> Maybe (JP.Index, NonEmpty err)
    validateElem schema (index,x) =
        (\v -> (index, v)) <$> NE.nonEmpty (f schema x)

--------------------------------------------------
-- * additionalItems
--------------------------------------------------