loadsmith-registry 0.2.0

Registry abstraction and built-in sources for the loadsmith mod-manager library
Documentation
//! Registry abstraction and built-in sources for the loadsmith mod-manager
//! library.
//!
//! This is an internal crate of the [`loadsmith`] workspace. Most consumers
//! should depend on the `loadsmith` facade crate instead of using this
//! crate directly.

use std::{collections::HashMap, fmt::Debug, pin::Pin};

use loadsmith_core::{Checksum, Dependency, FileUrl, PackageId, PackageRef, Version};

mod error;

mod registries;

pub use error::{Error, Result};
pub use registries::*;
use serde::de::DeserializeOwned;

#[derive(Debug, Clone)]
pub struct VersionInfo {
    pub version: Version,
}

#[derive(Debug, Clone)]
pub struct ResolvedVersion {
    pub url: FileUrl,
    pub size: Option<u64>,
    pub checksum: Option<Checksum>,
    pub deps: Vec<Dependency>,
}

pub trait Registry: Debug + Send + Sync {
    fn version_info<'a>(
        &'a self,
        id: &'a PackageId,
        metadata: Option<&'a serde_json::Value>,
    ) -> Pin<Box<dyn Future<Output = Result<Vec<VersionInfo>>> + 'a>>;

    fn resolve<'a>(
        &'a self,
        ref_: &'a PackageRef,
        metadata: Option<&'a serde_json::Value>,
    ) -> Pin<Box<dyn Future<Output = Result<ResolvedVersion>> + 'a>>;

    fn revalidate_checksum<'a>(
        &'a self,
        ref_: &'a PackageRef,
        metadata: Option<&'a serde_json::Value>,
    ) -> Result<Option<Checksum>> {
        let _ = (ref_, metadata);
        Ok(None)
    }
}

#[derive(Debug)]
pub struct RegistrySet {
    registries: HashMap<String, Box<dyn Registry>>,
}

impl Default for RegistrySet {
    fn default() -> Self {
        Self::new()
    }
}

impl RegistrySet {
    pub fn new() -> Self {
        Self {
            registries: HashMap::new(),
        }
    }

    pub fn add<R: Registry + 'static>(&mut self, id: impl Into<String>, registry: R) {
        self.registries.insert(id.into(), Box::new(registry));
    }

    pub fn get(&self, id: &str) -> Option<&dyn Registry> {
        self.registries.get(id).map(|r| r.as_ref())
    }
}

pub fn read_metadata_or_default<T: DeserializeOwned + Default>(
    metadata: Option<&serde_json::Value>,
) -> Result<T> {
    match metadata {
        Some(metadata) => read_metadata_some(metadata),
        None => Ok(T::default()),
    }
}

pub fn read_metadata<T: DeserializeOwned>(metadata: Option<&serde_json::Value>) -> Result<T> {
    match metadata {
        Some(metadata) => read_metadata_some(metadata),
        None => Err(Error::MissingMetadata),
    }
}

fn read_metadata_some<T: DeserializeOwned>(metadata: &serde_json::Value) -> Result<T> {
    serde_json::from_value(metadata.clone()).map_err(Error::InvalidMetadata)
}