use super::array::Iter as ZendHashTableIter;
use super::iterator::Iter as ZendIteratorIter;
use crate::convert::FromZvalMut;
use crate::flags::DataType;
use crate::types::{ZendHashTable, ZendIterator, Zval};
#[derive(Debug)]
pub enum Iterable<'a> {
Array(&'a ZendHashTable),
Traversable(&'a mut ZendIterator),
}
impl Iterable<'_> {
#[allow(clippy::iter_not_returning_iterator)]
pub fn iter(&mut self) -> Option<Iter<'_>> {
match self {
Iterable::Array(array) => Some(Iter::Array(array.iter())),
Iterable::Traversable(traversable) => Some(Iter::Traversable(traversable.iter()?)),
}
}
}
#[allow(clippy::into_iter_without_iter)]
impl<'a> IntoIterator for &'a mut Iterable<'a> {
type Item = (Zval, Zval);
type IntoIter = Iter<'a>;
#[expect(
clippy::expect_used,
reason = "IntoIterator has no error channel, and a fresh iterator can always be rewound"
)]
fn into_iter(self) -> Self::IntoIter {
self.iter().expect("Could not rewind iterator!")
}
}
impl<'a> FromZvalMut<'a> for Iterable<'a> {
const TYPE: DataType = DataType::Iterable;
fn from_zval_mut(zval: &'a mut Zval) -> Option<Self> {
if zval.is_traversable() {
return zval.traversable().map(Iterable::Traversable);
}
zval.array().map(Iterable::Array)
}
}
pub enum Iter<'a> {
Array(ZendHashTableIter<'a>),
Traversable(ZendIteratorIter<'a>),
}
impl Iterator for Iter<'_> {
type Item = (Zval, Zval);
fn next(&mut self) -> Option<Self::Item> {
match self {
Iter::Array(array) => array
.next_zval()
.map(|(key, value)| (key, value.shallow_clone())),
Iter::Traversable(traversable) => traversable.next(),
}
}
}