text: // -----------------------------------------------------------------------------------------------------
  // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
  // Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
  // This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
  // shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
  // -----------------------------------------------------------------------------------------------------
  
  /*!\file
   * \brief Provides seqan3::structure_file_input_format.
   * \author Jörg Winkler <j.winkler AT fu-berlin.de>
   */
  
  #pragma once
  
  #include <fstream>
  #include <set>
  #include <string>
  #include <utility>
  #include <vector>
  
  #include <seqan3/alphabet/nucleotide/rna5.hpp>
  #include <seqan3/alphabet/structure/structured_rna.hpp>
  #include <seqan3/alphabet/structure/wuss.hpp>
  #include <seqan3/core/type_list/type_list.hpp>
  #include <seqan3/io/structure_file/input_options.hpp>
  
  namespace seqan3::detail
  {
  
  /*!\brief Internal class used to expose the actual format interface to read structure records from the file.
   * \ingroup structure_file
   *
   * \tparam format_type The type of the format to be exposed.
   *
   * \details
   *
   * Exposes the protected member function `read_structure_record` from the given `format_type`, such that the file can
   * call the proper function for the selected format.
   */
  template <typename format_type>
  struct structure_file_input_format_exposer : public format_type
  {
  public:
      // Can't use `using format_type::read_structure_record` as it produces a hard failure in the format concept check
      // for types that do not model the format concept, i.e. don't offer the proper read_structure_record interface.
      //!\brief Forwards to the seqan3::structure_file_input_format::read_structure_record interface.
      template <typename ...ts>
      void read_structure_record(ts && ...args)
      {
          format_type::read_structure_record(std::forward<ts>(args)...);
      }
  };
  
  } // namespace seqan3::detail
  
  namespace seqan3
  {
  
  /*!\interface seqan3::structure_file_input_format <>
   * \brief The generic concept for structure file in formats.
   * \ingroup structure_file
   *
   * \details
   *
   * The details of this concept are only relevant to developers who wish to implement their own format.
   * The requirements for this concept are given as related functions and type traits.
   * Types that satisfy this concept are shown as "implementing this interface".
   */
  //!\cond
  template <typename t>
  SEQAN3_CONCEPT structure_file_input_format = requires(detail::structure_file_input_format_exposer<t> & v,
                                                        std::ifstream & f,
                                                        structure_file_input_options<rna5, false> & options,
                                                        rna5_vector & seq,
                                                        std::string & id,
                                                        std::vector<std::set<std::pair<double, size_t>>> & bpp,
                                                        std::vector<wuss51> & structure,
                                                        std::vector<structured_rna<rna5, wuss51>> & structured_seq,
                                                        double energy,
                                                        double react,
                                                        double react_err,
                                                        std::string & comment,
                                                        size_t offset)
  {
      t::file_extensions;
  
      SEQAN3_RETURN_TYPE_CONSTRAINT(v.read_structure_record(f,
                                                            options,
                                                            seq,
                                                            id,
                                                            bpp,
                                                            structure,
                                                            energy,
                                                            react,
                                                            react_err,
                                                            comment,
                                                            offset),
                                    std::same_as, void);
      SEQAN3_RETURN_TYPE_CONSTRAINT(v.read_structure_record(f,
                                                            options,
                                                            seq,
                                                            id,
                                                            bpp,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore),
                                    std::same_as, void);
      SEQAN3_RETURN_TYPE_CONSTRAINT(v.read_structure_record(f,
                                                            options,
                                                            structured_seq,
                                                            id,
                                                            std::ignore,
                                                            structured_seq,
                                                            energy,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore),
                                    std::same_as, void);
      SEQAN3_RETURN_TYPE_CONSTRAINT(v.read_structure_record(f,
                                                            options,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore,
                                                            std::ignore),
                                    std::same_as, void);
      // the last is required to be compile time valid, but should always throw at run-time.
  };
  //!\endcond
  
  /*!\name Requirements for seqan3::structure_file_input_format
   * \brief You can expect these **members** on all types that implement seqan3::structure_file_input_format.
   * \memberof seqan3::structure_file_input_format
   * \{
   */
  /*!\fn void read_structure_record(stream_type & stream,
   *                                structure_file_input_options<seq_legal_alph_type, structured_seq_combined> const & options,
   *                                seq_type & seq,
   *                                id_type & id,
   *                                bpp_type & bpp,
   *                                structure_type & structure,
   *                                energy_type & energy,
   *                                react_type & react,
   *                                react_type & react_err,
   *                                comment_type & comment,
   *                                offset_type & offset)
   * \brief Read from the specified stream and back-insert into the given field buffers.
   * \tparam stream_type      Input stream, must satisfy seqan3::input_stream_over with `char`.
   * \tparam seq_type         Type of the seqan3::field::seq input; must satisfy std::ranges::output_range
   * over a seqan3::alphabet.
   * \tparam id_type          Type of the seqan3::field::id input; must satisfy std::ranges::output_range
   * over a seqan3::alphabet.
   * \tparam bpp_type         Type of the seqan3::field::bpp input; must satisfy std::ranges::output_range
   * over a set of pair of types satisfying std::is_floating_point and std::numeric_limits::is_integer, respectively.
   * \tparam structure_type   Type of the seqan3::field::structure input; must satisfy std::ranges::output_range
   * over a seqan3::rna_structure_alphabet.
   * \tparam energy_type      Type of the seqan3::field::energy input; must satisfy std::is_floating_point.
   * \tparam react_type       Type of the seqan3::field::react and seqan3::field::react_err input;
   * must satisfy std::is_floating_point.
   * \tparam comment_type     Type of the seqan3::field::comment input; must satisfy std::ranges::output_range
   * over a seqan3::alphabet.
   * \tparam offset_type      Type of the seqan3::field::offset input; must satisfy std::numeric_limits::is_integer.
   * \param[in,out] stream    The input stream to read from.
   * \param[in]     options   File specific options passed to the format.
   * \param[out]    seq       The buffer for seqan3::field::seq input, i.e. the "sequence".
   * \param[out]    id        The buffer for seqan3::field::id input, e.g. the header line.
   * \param[out]    bpp       The buffer for seqan3::field::bpp input.
   * \param[out]    structure The buffer for seqan3::field::structure input.
   * \param[out]    energy    The buffer for seqan3::field::energy input.
   * \param[out]    react     The buffer for seqan3::field::react input.
   * \param[out]    react_err The buffer for seqan3::field::react_err input.
   * \param[out]    comment   The buffer for seqan3::field::comment input.
   * \param[out]    offset    The buffer for seqan3::field::offset input.
   *
   * \details
   *
   * ### Additional requirements
   *
   *   * The function must also accept std::ignore as parameter for any of the fields.
   *     [This is enforced by the concept checker!]
   *   * In this case the data read for that field shall be discarded by the format.
   *   * Instead of passing the fields seqan3::field::seq and seqan3::field::structure, you may also pass
   *     seqan3::field::structured_seq to both parameters. If you do, the std::ranges::range_value_t of the argument must be
   *     a specialisation of seqan3::structured_rna and the second template parameter to
   *     seqan3::structure_file_input_options must be set to true.
   */
   /*!\var static inline std::vector<std::string> seqan3::structure_file_input_format::file_extensions
   * \brief The format type is required to provide a vector of all supported file extensions.
   */
  //!\}
  
  } // namespace seqan3
  
  namespace seqan3::detail
  {
  
  /*!\brief Auxiliary value metafuncton that checks whether a type is a seqan3::type_list and all types meet
   * seqan3::structure_file_input_format [default is false].
   * \ingroup core
   * \see seqan3::type_list_specialisationOfstructure_file_input_formats
   */
  template <typename t>
  constexpr bool is_type_list_of_structure_file_input_formats_v = false;
  
  /*!\brief Auxiliary value metafuncton that checks whether a type is a seqan3::type_list and all types meet
   * seqan3::structure_file_input_format [overload].
   * \ingroup core
   * \see seqan3::type_list_specialisationOfstructure_file_input_formats
   */
  template <typename ...ts>
  constexpr bool is_type_list_of_structure_file_input_formats_v<type_list<ts...>>
                  = (structure_file_input_format<ts> && ...);
  
  /*!\brief Auxiliary concept that checks whether a type is a seqan3::type_list and all types meet
   * seqan3::structure_file_input_format.
   * \ingroup core
   * \see seqan3::is_type_list_of_structure_file_formats_v
   */
  template <typename t>
  SEQAN3_CONCEPT type_list_of_structure_file_input_formats = is_type_list_of_structure_file_input_formats_v<t>;
  } // namespace seqan3::detail
  