use
experimental
qw( signatures declared_refs refaliasing )
;
our
$VERSION
=
'0.18'
;
sub
new (
$class
,
@args
) {
my
$pars
= Ref::Util::is_hashref(
$args
[-1] ) ?
pop
@args
: {};
@args
or
$class
->_throw(
parameter
=>
'not enough parameters'
);
$class
->SUPER::new( {
depends
=> \
@args
,
current_iterator_index
=>
undef
,
},
$pars
);
}
sub
construct (
$class
,
$state
) {
$class
->_throw(
parameter
=>
"state must be a HASH reference"
)
unless
Ref::Util::is_hashref(
$state
);
$state
->{value} //= [];
my
( \
@depends
,
$current_iterator_index
,
$prev
,
$current
,
$next
,
$thaw
)
= @{
$state
}{
'depends'
,
'current_iterator_index'
,
'prev'
,
'current'
,
'next'
,
'thaw'
};
my
@iterators
=
map
{ Iterator::Flex::Factory->to_iterator(
$_
, { ( +EXHAUSTION ) => +RETURN } ) }
@depends
;
my
$value
;
$value
=
$current
if
$thaw
;
my
$self
;
my
$iterator_state
;
my
%params
= (
( +_SELF ) => \
$self
,
( +STATE ) => \
$iterator_state
,
( +NEXT ) =>
sub
{
return
$self
->signal_exhaustion
if
$iterator_state
== +IterState_EXHAUSTED;
$current_iterator_index
= 0
if
!
defined
$current_iterator_index
;
for
( ;
$current_iterator_index
<
@iterators
;
$current_iterator_index
++ ) {
my
$iter
=
$iterators
[
$current_iterator_index
];
my
$value
=
$iter
->();
unless
(
$iter
->is_exhausted ) {
$prev
=
$current
;
$current
=
$value
;
return
$current
;
}
}
$prev
=
$current
;
return
$current
=
$self
->signal_exhaustion;
},
( +PREV ) =>
sub
{
return
$prev
;
},
( +CURRENT ) =>
sub
{
return
$self
->signal_exhaustion
if
$iterator_state
eq +IterState_EXHAUSTED;
return
$current
;
},
( +_ROLES ) => [],
( +_DEPENDS ) => \
@iterators
,
);
if
( all {
defined
$class
->_can_meth(
$_
,
'current'
) }
@iterators
) {
$params
{ +FREEZE } =
sub
{
return
[
$class
,
{
current_iterator_index
=>
$current_iterator_index
,
prev
=>
$prev
,
current
=>
$current
,
next
=>
$next
,
} ];
};
push
$params
{ +_ROLES }->@*,
'Freeze'
;
}
if
( all {
defined
$class
->_can_meth(
$_
,
'reset'
) }
@iterators
) {
$params
{ +RESET } =
sub
{
$prev
=
$current
=
undef
;
$current_iterator_index
=
undef
;
};
push
$params
{ +_ROLES }->@*,
'Reset::Closure'
;
}
if
( all {
defined
$class
->_can_meth(
$_
,
'rewind'
) }
@iterators
) {
$params
{ +REWIND } =
sub
{
$current_iterator_index
=
undef
; };
push
$params
{ +_ROLES }->@*,
'Rewind::Closure'
;
}
$params
{ +_NAME } =
'icat'
;
return
\
%params
;
}
__PACKAGE__->_add_roles(
qw[
State::Closure
Next::ClosedSelf
Current::Closure
Prev::Closure
]
);
1;