Skip to main content

use_oci_index/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use use_oci_annotation::Annotation;
5use use_oci_descriptor::OciDescriptor;
6use use_oci_platform::OciPlatform;
7
8/// A platform-specific manifest reference in an OCI image index.
9#[derive(Clone, Debug, Eq, PartialEq)]
10pub struct IndexManifest {
11    descriptor: OciDescriptor,
12    platform: Option<OciPlatform>,
13    annotations: Vec<Annotation>,
14}
15
16impl IndexManifest {
17    /// Creates an index manifest reference.
18    #[must_use]
19    pub fn new(descriptor: OciDescriptor) -> Self {
20        Self {
21            descriptor,
22            platform: None,
23            annotations: Vec::new(),
24        }
25    }
26
27    /// Adds platform metadata.
28    #[must_use]
29    pub fn with_platform(mut self, platform: OciPlatform) -> Self {
30        self.platform = Some(platform);
31        self
32    }
33
34    /// Adds an annotation.
35    #[must_use]
36    pub fn with_annotation(mut self, annotation: Annotation) -> Self {
37        self.annotations.push(annotation);
38        self
39    }
40
41    /// Returns the descriptor.
42    #[must_use]
43    pub const fn descriptor(&self) -> &OciDescriptor {
44        &self.descriptor
45    }
46
47    /// Returns the optional platform.
48    #[must_use]
49    pub const fn platform(&self) -> Option<&OciPlatform> {
50        self.platform.as_ref()
51    }
52
53    /// Returns annotations.
54    #[must_use]
55    pub fn annotations(&self) -> &[Annotation] {
56        &self.annotations
57    }
58}
59
60/// OCI image index metadata.
61#[derive(Clone, Debug, Default, Eq, PartialEq)]
62pub struct OciIndex {
63    manifests: Vec<IndexManifest>,
64    annotations: Vec<Annotation>,
65}
66
67impl OciIndex {
68    /// Creates an empty image index.
69    #[must_use]
70    pub const fn new() -> Self {
71        Self {
72            manifests: Vec::new(),
73            annotations: Vec::new(),
74        }
75    }
76
77    /// Adds a manifest reference.
78    #[must_use]
79    pub fn with_manifest(mut self, manifest: IndexManifest) -> Self {
80        self.manifests.push(manifest);
81        self
82    }
83
84    /// Adds an annotation.
85    #[must_use]
86    pub fn with_annotation(mut self, annotation: Annotation) -> Self {
87        self.annotations.push(annotation);
88        self
89    }
90
91    /// Returns manifest references.
92    #[must_use]
93    pub fn manifests(&self) -> &[IndexManifest] {
94        &self.manifests
95    }
96
97    /// Returns index annotations.
98    #[must_use]
99    pub fn annotations(&self) -> &[Annotation] {
100        &self.annotations
101    }
102}
103
104/// Lightweight index metadata counters.
105#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
106pub struct IndexMetadata {
107    manifest_count: usize,
108}
109
110impl IndexMetadata {
111    /// Creates index metadata.
112    #[must_use]
113    pub const fn new(manifest_count: usize) -> Self {
114        Self { manifest_count }
115    }
116
117    /// Returns the manifest count.
118    #[must_use]
119    pub const fn manifest_count(self) -> usize {
120        self.manifest_count
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    use super::{IndexManifest, IndexMetadata, OciIndex};
127    use use_oci_descriptor::{DescriptorSize, OciDescriptor};
128    use use_oci_digest::OciDigest;
129    use use_oci_media_type::OciMediaType;
130    use use_oci_platform::{OciArchitecture, OciOs, OciPlatform};
131
132    const SHA: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
133
134    #[test]
135    fn models_index_entries() -> Result<(), Box<dyn std::error::Error>> {
136        let digest: OciDigest = format!("sha256:{SHA}").parse()?;
137        let descriptor = OciDescriptor::new(
138            OciMediaType::image_manifest(),
139            digest,
140            DescriptorSize::new(10),
141        );
142        let platform = OciPlatform::new(OciOs::Linux, OciArchitecture::Arm64);
143        let entry = IndexManifest::new(descriptor).with_platform(platform.clone());
144        let index = OciIndex::new().with_manifest(entry);
145
146        assert_eq!(index.manifests().len(), 1);
147        assert_eq!(index.manifests()[0].platform(), Some(&platform));
148        assert_eq!(
149            IndexMetadata::new(index.manifests().len()).manifest_count(),
150            1
151        );
152        Ok(())
153    }
154}