compose_lens/model/
image.rs1#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5pub struct ImageDigest {
6 algorithm: Option<String>,
7 value: String,
8}
9
10impl ImageDigest {
11 #[must_use]
13 pub fn algorithm(&self) -> Option<&str> {
14 self.algorithm.as_deref()
15 }
16
17 #[must_use]
19 pub fn value(&self) -> &str {
20 &self.value
21 }
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Hash)]
30pub struct ImageReference {
31 raw: String,
32 name: String,
33 tag: Option<String>,
34 digest: Option<ImageDigest>,
35}
36
37impl ImageReference {
38 pub(crate) fn parse(raw: String) -> Self {
39 let (name_and_tag, digest) = raw.split_once('@').map_or((raw.as_str(), None), |(left, right)| {
40 let (algorithm, value) = right
41 .split_once(':')
42 .map_or((None, right.to_owned()), |(algorithm, value)| {
43 (Some(algorithm.to_owned()), value.to_owned())
44 });
45 (left, Some(ImageDigest { algorithm, value }))
46 });
47
48 let last_slash = name_and_tag.rfind('/');
49 let tag_separator = name_and_tag
50 .rfind(':')
51 .filter(|index| last_slash.is_none_or(|slash| *index > slash));
52 let (name, tag) = tag_separator.map_or_else(
53 || (name_and_tag.to_owned(), None),
54 |index| {
55 (
56 name_and_tag[..index].to_owned(),
57 Some(name_and_tag[index + 1..].to_owned()),
58 )
59 },
60 );
61
62 Self { raw, name, tag, digest }
63 }
64
65 #[must_use]
67 pub fn raw(&self) -> &str {
68 &self.raw
69 }
70
71 #[must_use]
73 pub fn name(&self) -> &str {
74 &self.name
75 }
76
77 #[must_use]
79 pub fn tag(&self) -> Option<&str> {
80 self.tag.as_deref()
81 }
82
83 #[must_use]
85 pub const fn digest(&self) -> Option<&ImageDigest> {
86 self.digest.as_ref()
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::ImageReference;
93
94 #[test]
95 fn accepts_registry_ports_tags_and_digests_together() {
96 let reference = ImageReference::parse("registry.example:5000/team/app:1.2@sha256:abcdef".to_owned());
97
98 assert_eq!(reference.name(), "registry.example:5000/team/app");
99 assert_eq!(reference.tag(), Some("1.2"));
100 assert_eq!(
101 reference.digest().and_then(super::ImageDigest::algorithm),
102 Some("sha256")
103 );
104 assert_eq!(reference.digest().map(super::ImageDigest::value), Some("abcdef"));
105 }
106}