trustfall_rustdoc 0.39.0

Run Trustfall queries across multiple rustdoc JSON format versions.
Documentation
use std::fmt::Debug;

use anyhow::bail;
use trustfall::Schema;

macro_rules! add_version_method {
    () => {
        pub fn version(&self) -> u32 {
            match self {
                {{#each version_numbers}}
                #[cfg(feature = "v{{this}}")]
                Self::V{{this}}(..) => {{this}},

                {{/each}}
            }
        }
    };
}

#[non_exhaustive]
#[derive(Debug)]
pub enum VersionedStorage {
    {{#each version_numbers}}
    #[cfg(feature = "v{{this}}")]
    V{{this}}(trustfall_rustdoc_adapter_v{{this}}::PackageStorage),

    {{/each}}
}

#[non_exhaustive]
#[derive(Debug)]
pub enum VersionedIndex<'a> {
    {{#each version_numbers}}
    #[cfg(feature = "v{{this}}")]
    V{{this}}(trustfall_rustdoc_adapter_v{{this}}::PackageIndex<'a>),

    {{/each}}
}

#[non_exhaustive]
pub enum VersionedRustdocAdapter<'a> {
    {{#each version_numbers}}
    #[cfg(feature = "v{{this}}")]
    V{{this}}(
        &'static Schema,
        trustfall_rustdoc_adapter_v{{this}}::RustdocAdapter<'a>,
    ),

    {{/each}}
}

impl VersionedStorage {
    /// The version of the crate held here, as reported by its rustdoc data.
    ///
    /// This is the version listed in the `Cargo.toml` of the crate, not its rustdoc format version.
    pub fn crate_version(&self) -> Option<&str> {
        match self {
            {{#each version_numbers}}
            #[cfg(feature = "v{{this}}")]
            VersionedStorage::V{{this}}(s) => s.crate_version(),

            {{/each}}
        }
    }

    add_version_method!();
}

impl<'a> VersionedIndex<'a> {
    pub fn from_storage(storage: &'a VersionedStorage) -> Self {
        match storage {
            {{#each version_numbers}}
            #[cfg(feature = "v{{this}}")]
            VersionedStorage::V{{this}}(s) => Self::V{{this}}(
                trustfall_rustdoc_adapter_v{{this}}::PackageIndex::from_storage(s),
            ),

            {{/each}}
        }
    }

    /// Build an index for Rust standard-library component rustdoc JSON.
    ///
    /// This opts into adapter-side standard-library stability rules. Use
    /// [`Self::from_storage`] for ordinary crates.
    pub fn from_rust_std_component_storage(storage: &'a VersionedStorage) -> Self {
        match storage {
            {{#each version_numbers}}
            #[cfg(feature = "v{{this}}")]
            VersionedStorage::V{{this}}(s) => Self::V{{this}}(
                trustfall_rustdoc_adapter_v{{this}}::PackageIndex::from_rust_std_component_storage(s),
            ),

            {{/each}}
        }
    }

    add_version_method!();
}

impl<'a> VersionedRustdocAdapter<'a> {
    pub fn new(
        current: &'a VersionedIndex<'a>,
        baseline: Option<&'a VersionedIndex<'a>>,
    ) -> anyhow::Result<Self> {
        match (current, baseline) {
            {{#each version_numbers}}
            #[cfg(feature = "v{{this}}")]
            (VersionedIndex::V{{this}}(c), Some(VersionedIndex::V{{this}}(b))) => {
                let adapter = trustfall_rustdoc_adapter_v{{this}}::RustdocAdapter::new(
                    c,
                    Some(b),
                );
                Ok(VersionedRustdocAdapter::V{{this}}(
                    trustfall_rustdoc_adapter_v{{this}}::RustdocAdapter::schema(),
                    adapter,
                ))
            }

            #[cfg(feature = "v{{this}}")]
            (VersionedIndex::V{{this}}(c), None) => {
                let adapter = trustfall_rustdoc_adapter_v{{this}}::RustdocAdapter::new(c, None);
                Ok(VersionedRustdocAdapter::V{{this}}(
                    trustfall_rustdoc_adapter_v{{this}}::RustdocAdapter::schema(),
                    adapter,
                ))
            }

            {{/each}}
            #[allow(unreachable_patterns)]
            (c, Some(b)) => {
                bail!(
                    "version mismatch between current (v{}) and baseline (v{}) format versions",
                    c.version(),
                    b.version()
                )
            }
        }
    }

    pub fn schema(&self) -> &Schema {
        match self {
            {{#each version_numbers}}
            #[cfg(feature = "v{{this}}")]
            VersionedRustdocAdapter::V{{this}}(schema, ..) => schema,

            {{/each}}
        }
    }

    add_version_method!();
}

pub(crate) fn supported_versions() -> &'static [u32] {
    &[
        {{#each version_numbers}}
        #[cfg(feature = "v{{this}}")]
        {{this}},
        {{/each}}
    ]
}