#![warn(missing_docs)]
//! Parse configuration files.
//!
//! The `confget` library parses configuration files (currently INI-style
//! files only) and allows a program to use the values defined in them.
//! It provides various options for selecting the variable names and
//! values to return and the configuration file sections to fetch them from.
//!
//! The `confget` library may also be used as a command-line tool with
//! the same interface as the C implementation.
//!
//! # Quick-and-easy parsing of INI-style files
//!
//! The [`read_ini_file`] function will parse
//! an INI-style file and return a hashmap of the values found in its
//! various sections, as well as the name of the first section found in
//! the file (or the one specified in the configuration if
//! the [`Config::section_override`] option is enabled).
//!
//! ```
//! # use std::error::Error;
//! # use std::fs;
//! # use std::path::Path;
//!
//! # use confget::Config;
//!
//! # fn main() -> Result<(), Box<dyn Error>> {
//! # let tempd_obj = tempfile::tempdir()?;
//! # let confdir: &Path = tempd_obj.as_ref();
//! # fs::write(&confdir.join("config.ini"), "var = value\n");
//! // Default configuration except for the filename.
//! let config = Config {
//!     filename: Some(confdir.join("config.ini").to_str().unwrap().to_string()),
//!     ..Config::default()
//! };
//! let (data, first_section) = confget::read_ini_file(&config)?;
//! # Ok(())
//! # }
//! ```
//!
//! For the crate's change history, see
//! the [CHANGES](https://gitlab.com/confget/confget/-/blob/master/CHANGES)
//! file in the source distribution.

#![doc(html_root_url = "https://docs.rs/confget/4.1.1")]
/*
 * Copyright (c) 2021, 2022  Peter Pentchev <roam@ringlet.net>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
// We want to re-export some defs::* types to make it easier on the consumers.
#![allow(clippy::pub_use)]

use std::error::Error;

use crate::backend::ini::IniBackend;
use crate::backend::{Backend, DataRead};

pub mod backend;
pub mod defs;
pub mod format;

pub use defs::{BackendKind, ConfgetError, Config};

/// Construct an object of the specified backend type.
///
/// The `backend` member of the [`Config`] object
/// specifies the type of the backend to construct.
///
/// Some backends may perform validation at object creation time;
/// the "ini" one currently does not, so this method will always succeed.
///
/// # Errors
///
/// None for the present, but future backends may check for configuration
/// inconsistencies.
#[inline]
pub fn get_backend<'cfg>(config: &'cfg Config) -> Result<Box<dyn Backend + 'cfg>, Box<dyn Error>> {
    match config.backend {
        BackendKind::Ini => Ok(Box::new(IniBackend { config })),
    }
}

/// Read an INI-style file with the specified configuration.
///
/// Internally constructs an "ini" backend and invokes its
/// [`Backend::read_file`] method.
/// The [`Config`] object's `filename` member must contain a value.
///
/// # Errors
///
/// The same as from [`IniBackend::read_file`].
#[inline]
pub fn read_ini_file(config: &Config) -> Result<DataRead, Box<dyn Error>> {
    let ini = IniBackend { config };
    ini.read_file()
}
