//! Top-level discovery entry point.
//!
//! [`Discovery`] borrows a [`Filesystem`] implementation and
//! exposes every discovery operation as a method on the borrowed
//! reference. Per the crate's generics-containment strategy, call
//! sites construct a single `Discovery<F>` per workflow and invoke
//! methods on it, rather than passing `&F` to free functions at
//! each call.
//!
//! The struct itself is defined here; the methods that implement
//! the spec rules live alongside the data types they produce, in
//! [`crate::root::walk`] (workspace-root walk) and
//! [`crate::workspace::load`] (workspace-config loader).
//!
//! [`Filesystem`]: haz_vfs::Filesystem

use haz_vfs::Filesystem;

/// Holds a borrowed [`Filesystem`] implementation for the duration
/// of a discovery workflow.
///
/// All discovery operations are methods on this struct; this crate
/// exposes no top-level free functions. Constructing a
/// `Discovery<F>` is the entry point.
///
/// # Examples
///
/// ```
/// use haz_vfs_testing::MemFilesystem;
/// use haz_discovery::discovery::Discovery;
///
/// let fs = MemFilesystem::new();
/// let discovery = Discovery::new(&fs);
/// // discovery.discover_workspace(start_dir) drives the full
/// // discovery + load pipeline.
/// let _ = discovery.fs();
/// ```
pub struct Discovery<'fs, F: Filesystem> {
    pub(crate) fs: &'fs F,
}

impl<'fs, F: Filesystem> Discovery<'fs, F> {
    /// Construct a [`Discovery`] borrowing the supplied filesystem
    /// for as long as `self` lives.
    #[must_use]
    pub fn new(fs: &'fs F) -> Self {
        Self { fs }
    }

    /// Borrow the underlying filesystem implementation.
    #[must_use]
    pub fn fs(&self) -> &'fs F {
        self.fs
    }
}
