!===========================================
! Author: Elmo Tempel (elmo.tempel@ut.ee)
!===========================================
!> Reading and writing Parquet files, and nothing else: the minimal supported
!> entry point for a program that opens a file, moves columns in or out of it,
!> and closes it again.
!>
!> A single `use parquet_io` brings in the readers, writers, schemas, MAML
!> parsing and validation, row filters, sort keys, read-time quality control and
!> flat key-value file metadata -- together with the element types those calls
!> take and return (`parquet_string_column`/`parquet_string`, `parquet_date`/
!> `parquet_time`/`parquet_timestamp` and their unit selectors, and
!> `parquet_maml_file`) -- plus the process-global settings, so that a program
!> importing this module alone can still choose a writer's compression, cap the
!> library's threads, or silence what it prints.
!>
!> **What it deliberately leaves out** is everything that is not I/O: the
!> `parquet_table` container (`use parquet_tables`), the `parquet_column`
!> foundation (`use parquet_columns`), sorting (`use parquet_sorting` or
!> `use parquet_argsort`), random numbers (`use parquet_random`) and sampling
!> (`use parquet_sampling`). Each of those is its own entry module; `use parquet`
!> is the facade that carries all of them at once.
!>
!> That list is about the NAMESPACE, not about what fpm compiles, and
!> `parquet_random` is the one place the two differ: `pf_random_at` and its
!> siblings are not reachable from `use parquet_io`, but the reader draws
!> `sample_fraction=`'s rows with that generator, so its three-file leaf tier is
!> compiled for this import. The footprint table in
!> doc/pages/operating/choosing-a-module.md counts them.
!>
!> **This module does not make the library Arrow-free.** Reading and writing a
!> Parquet file *is* the Arrow-facing half of parquet-fortran, so this module's
!> graph reaches `parquet_bindings` and the C++ wrapper by design -- unlike
!> `parquet_argsort`, `parquet_sampling`, `parquet_sorting`, `parquet_strings`,
!> `parquet_temporal`, `parquet_columns`, `parquet_random` and `parquet_version`,
!> whose Fortran graphs do not. Note that no module makes the *package* Arrow-free: `link` is a
!> package-level key in `fpm.toml`, so `src/parquet_wrapper.cpp` is compiled and
!> `-larrow -larrow_compute -lparquet` linked whichever module you import. See
!> doc/pages/operating/choosing-a-module.md.
!>
!> Like the `parquet` facade, this is a re-export shell with no code of its own:
!> `parquet_core` and `parquet_settings` hold the implementations, and this
!> module exists so that neither of those names has to appear in user code.
!> `parquet_core` remains internal and may change in any release; `parquet_io`
!> is covered by the library's semantic-versioning promise. One consequence of
!> the facade shape is that FORD does not list the re-exported names as
!> belonging to this module, so its generated page is nearly empty -- the names
!> are in the site-wide procedure and type listings instead, exactly as
!> CLAUDE.md records for `module/parquet.html`.
module parquet_io
    use parquet_core
    use parquet_settings
    implicit none
    !
    ! Default accessibility is deliberately PUBLIC here, as in src/parquet.f90 and for the same
    ! reason: a bare `use <sibling>` with no `only:` list re-exports that module's whole public
    ! surface, which is what a facade wants and what avoids maintaining a name list that would go
    ! stale on every addition. The `private ::` statements below are the only thing keeping
    ! cross-module plumbing out of the namespace a user gets from `use parquet_io`. Each mirrors a
    ! statement in src/parquet.f90 -- the two facades must hide the same names, or `use parquet_io`
    ! would expose something `use parquet` does not.
    !
    ! parquet_core has to make these two public so the sibling parquet_tables module can reach
    ! them: parquet_split_name_list is the library's one name-list tokenizer and
    ! parquet_parse_sort_key its one sort-key direction grammar, shared so the table layer and the
    ! reader cannot disagree about punctuation. Plumbing, not API.
    private :: parquet_split_name_list
    private :: parquet_parse_sort_key
    ! parquet_settings has to make these public so the write path (a submodule of parquet_core, a
    ! different module) can resolve a compression token, and so every module that emits can reach
    ! the output channels. Same case again: public for want of package scope, hidden here.
    private :: parquet_valid_compressions, parquet_resolve_writer_compression
    private :: parquet_emit_info, parquet_emit_warning, parquet_emit_error_context
    private :: parquet_output_is_suppressed
    private :: parquet_clamp_to_affinity
    ! The Fortran->C++ mirror push: parquet_read and parquet_write (both submodules of a DIFFERENT
    ! module) call it when a reader or writer opens, so parquet_settings must make it public.
    ! parquet_validity_block_bits needs no line here -- it belongs to parquet_columns, which this
    ! facade does not re-export.
    private :: parquet_push_settings_to_cpp
end module parquet_io
