/** Stream iterators.
 *
 * Copyright (c) 2000-2026, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this
 * mistake, or contact the author.
 */
#ifndef PQXX_INTERNAL_STREAM_ITERATOR_HXX
#define PQXX_INTERNAL_STREAM_ITERATOR_HXX

#include <memory>

namespace pqxx
{
template<typename... TYPE> class stream_query;
} // namespace pqxx


namespace pqxx::internal
{
/// Input iterator for stream_from.
/** Just barely enough to support range-based "for" loops on stream_from.
 * Don't assume that any of the usual behaviour works beyond that.
 */
template<typename... TYPE> class stream_from_input_iterator final
{
  using stream_t = stream_from;

public:
  using value_type = std::tuple<TYPE...>;

  /// Construct an "end" iterator.
  stream_from_input_iterator() = default;

  explicit stream_from_input_iterator(stream_t &home, sl loc) : m_home(&home)
  {
    advance(loc);
  }
  stream_from_input_iterator(stream_from_input_iterator const &) = default;
  stream_from_input_iterator(stream_from_input_iterator &&) = default;

  stream_from_input_iterator &operator++()
  {
    advance(sl::current());
    return *this;
  }

  ~stream_from_input_iterator() = default;

  stream_from_input_iterator &
  operator=(stream_from_input_iterator const &) = default;
  stream_from_input_iterator &
  operator=(stream_from_input_iterator &&) = default;

  value_type const &operator*() const noexcept { return m_value; }

  /// Comparison only works for comparing to end().
  bool operator==(stream_from_input_iterator const &rhs) const noexcept
  {
    return m_home == rhs.m_home;
  }
  /// Comparison only works for comparing to end().
  bool operator!=(stream_from_input_iterator const &rhs) const noexcept
  {
    return not(*this == rhs);
  }

private:
  void advance(sl loc)
  {
    if (m_home == nullptr)
      throw usage_error{"Moving stream_from iterator beyond end().", loc};
    if (not((*m_home) >> m_value))
      m_home = nullptr;
  }

  stream_t *m_home{nullptr};
  value_type m_value;
};


// TODO: Use separate type for end().
// TODO: Replace with generator?
/// Iteration over a @ref stream_query.
template<typename... TYPE> class stream_input_iteration final
{
public:
  using stream_t = stream_from;
  using iterator = stream_from_input_iterator<TYPE...>;
  explicit stream_input_iteration(stream_t &home) : m_home{home} {}
  [[nodiscard]] iterator begin(sl loc = sl::current()) const
  {
    return iterator{m_home, loc};
  }
  [[nodiscard]] iterator end() const { return {}; }

private:
  // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
  stream_t &m_home;
};
} // namespace pqxx::internal
#endif
