wadm_client/
loader.rs

1//! Various helpers and traits for loading and parsing manifests
2
3use std::{
4    future::Future,
5    path::{Path, PathBuf},
6};
7
8use wadm_types::Manifest;
9
10use crate::{error::ClientError, Result};
11
12/// A trait for loading a [`Manifest`] from a variety of sources. This is also used as a convenience
13/// trait in the client for easily passing in any type of Manifest
14pub trait ManifestLoader {
15    fn load_manifest(self) -> impl Future<Output = Result<Manifest>>;
16}
17
18impl ManifestLoader for &Manifest {
19    async fn load_manifest(self) -> Result<Manifest> {
20        Ok(self.clone())
21    }
22}
23
24impl ManifestLoader for Manifest {
25    async fn load_manifest(self) -> Result<Manifest> {
26        Ok(self)
27    }
28}
29
30impl ManifestLoader for Vec<u8> {
31    async fn load_manifest(self) -> Result<Manifest> {
32        parse_yaml_or_json(self).map_err(Into::into)
33    }
34}
35
36impl ManifestLoader for &[u8] {
37    async fn load_manifest(self) -> Result<Manifest> {
38        parse_yaml_or_json(self).map_err(Into::into)
39    }
40}
41
42// Helper macro for implementing `ManifestLoader` for anything that implements `AsRef<Path>` (which
43// results in a compiler error if we do it generically)
44macro_rules! impl_manifest_loader_for_path {
45    ($($ty:ty),*) => {
46        $(
47            impl ManifestLoader for $ty {
48                async fn load_manifest(self) -> Result<Manifest> {
49                    let raw = tokio::fs::read(self).await.map_err(|e| ClientError::ManifestLoad(e.into()))?;
50                    parse_yaml_or_json(raw).map_err(Into::into)
51                }
52            }
53        )*
54    };
55}
56
57impl_manifest_loader_for_path!(&Path, &str, &String, String, PathBuf, &PathBuf);
58
59/// A simple function that attempts to parse the given bytes as YAML or JSON. This is used in the
60/// implementations of `ManifestLoader`
61pub fn parse_yaml_or_json(
62    raw: impl AsRef<[u8]>,
63) -> std::result::Result<Manifest, crate::error::SerializationError> {
64    // Attempt to parse as YAML first, then JSON
65    serde_yaml::from_slice(raw.as_ref())
66        .or_else(|_| serde_json::from_slice(raw.as_ref()))
67        .map_err(Into::into)
68}