1. # A SlippyIterator is one that comes with some infrastructure for handling
  2. # flattening a received Slip into its own stream of values.
  3. my role SlippyIterator does Iterator {
  4. # Flat set to non-zero if the iterator is currently consuming a Slip.
  5. has int $!slipping;
  6. # The current Slip we're iterating.
  7. has $!slip-iter;
  8. proto method start-slip(|) { * }
  9. multi method start-slip(Slip:U $slip) {
  10. $slip
  11. }
  12. multi method start-slip(Slip:D $slip) {
  13. nqp::if(
  14. nqp::eqaddr($slip,Empty),
  15. IterationEnd, # we know there's nothing
  16. nqp::if(
  17. nqp::eqaddr(
  18. (my \result := ($!slip-iter := $slip.iterator).pull-one),
  19. IterationEnd
  20. ),
  21. IterationEnd, # we've determined there's nothing
  22. nqp::stmts( # need to start a Slip
  23. ($!slipping = 1),
  24. result
  25. )
  26. )
  27. )
  28. }
  29. method slip-one() {
  30. nqp::stmts(
  31. nqp::if(
  32. nqp::eqaddr((my \result := $!slip-iter.pull-one),IterationEnd),
  33. nqp::stmts(
  34. ($!slipping = 0),
  35. ($!slip-iter := nqp::null)
  36. )
  37. ),
  38. result
  39. )
  40. }
  41. proto method slip-all(|) { * }
  42. multi method slip-all(Slip:U $slip, $target) {
  43. $target.push($slip)
  44. }
  45. multi method slip-all(Slip:D $slip, $target) {
  46. nqp::unless(
  47. nqp::eqaddr($slip,Empty),
  48. $slip.iterator.push-all($target)
  49. )
  50. }
  51. }