arch_pkg_text/srcinfo/query/
checksums.rs

1use crate::{
2    srcinfo::field::FieldName,
3    value::{self, ParseArray, SkipOrArray},
4};
5use pipe_trait::Pipe;
6
7macro_rules! def_enum {
8    ($(
9        $checksum_variant:ident($checksum_content:ident, $size:literal) = $field_variant:ident,
10    )*) => {
11        /// Type of checksum.
12        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13        pub enum ChecksumType {$(
14            $checksum_variant,
15        )*}
16
17        impl ChecksumType {
18            /// All recognized checksum types.
19            pub const TYPES: &[Self] = &[$(ChecksumType::$checksum_variant,)*];
20
21            /// All recognized checksum types.
22            pub fn all_types() -> impl Iterator<Item = &'static Self> {
23                ChecksumType::TYPES.iter()
24            }
25
26            /// Convert a [`ChecksumType`] into a corresponding [`FieldName`].
27            pub const fn into_field_name(self) -> FieldName {
28                match self {$(
29                    ChecksumType::$checksum_variant => FieldName::$field_variant,
30                )*}
31            }
32
33            /// Try converting a [`FieldName`] into a corresponding [`ChecksumType`].
34            pub const fn try_from_field_name(field_name: FieldName) -> Option<Self> {
35                match field_name {
36                    $(FieldName::$field_variant => Some(ChecksumType::$checksum_variant),)*
37                    _ => None,
38                }
39            }
40        }
41
42        /// Value of checksum.
43        #[derive(Debug, Clone, Copy)]
44        pub enum ChecksumValue<'a> {$(
45            $checksum_variant(value::$checksum_content<'a>),
46        )*}
47
48        impl<'a> ChecksumValue<'a> {
49            /// Create a [`ChecksumValue`] from a [`ChecksumType`] and a raw value.
50            pub fn new(checksum_type: ChecksumType, raw_value: &'a str) -> Self {
51                match checksum_type {$(
52                    ChecksumType::$checksum_variant => {
53                        raw_value.pipe(value::$checksum_content).pipe(ChecksumValue::$checksum_variant)
54                    }
55                )*}
56            }
57
58            /// Attempt to create a [`ChecksumValue`] from a [`FieldName`] and a raw value.
59            pub(super) fn try_from_field_name(field_name: FieldName, raw_value: &'a str) -> Option<Self> {
60                let checksum_type = ChecksumType::try_from_field_name(field_name)?;
61                Some(ChecksumValue::new(checksum_type, raw_value))
62            }
63        }
64
65        /// [Array type](ParseArray::Array) of [`ChecksumValue`].
66        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67        pub enum ChecksumArray {
68            Skip,
69            $($checksum_variant([u8; $size]),)*
70        }
71
72        impl<'a> ChecksumValue<'a> {
73            /// Convert the hex string into an array of 8-bit unsigned integers.
74            pub fn u8_array(self) -> Option<ChecksumArray> {
75                Some(match self {$(
76                    ChecksumValue::$checksum_variant(hex_string) => match hex_string.u8_array()? {
77                        SkipOrArray::Skip => ChecksumArray::Skip,
78                        SkipOrArray::Array(array) => ChecksumArray::$checksum_variant(array),
79                    }
80                )*})
81            }
82        }
83
84        impl ChecksumArray {
85            /// Get a slice of the internal array if it wasn't [`ChecksumArray::Skip`].
86            pub fn try_as_slice(&self) -> Option<&'_ [u8]> {
87                match self {
88                    ChecksumArray::Skip => None,
89                    $(ChecksumArray::$checksum_variant(array) => Some(array),)*
90                }
91            }
92        }
93    };
94}
95
96def_enum! {
97    Md5(SkipOrHex128, 16) = Md5Checksums,
98    Sha1(SkipOrHex160, 20) = Sha1Checksums,
99    Sha224(SkipOrHex224, 28) = Sha224Checksums,
100    Sha256(SkipOrHex256, 32) = Sha256Checksums,
101    Sha384(SkipOrHex384, 48) = Sha384Checksums,
102    Sha512(SkipOrHex512, 64) = Sha512Checksums,
103    Blake2b(SkipOrHex512, 64) = Blake2bChecksums,
104}
105
106impl From<ChecksumType> for FieldName {
107    fn from(value: ChecksumType) -> Self {
108        value.into_field_name()
109    }
110}
111
112impl TryFrom<FieldName> for ChecksumType {
113    type Error = ();
114    fn try_from(value: FieldName) -> Result<Self, Self::Error> {
115        ChecksumType::try_from_field_name(value).ok_or(())
116    }
117}
118
119impl ParseArray for ChecksumValue<'_> {
120    type Array = ChecksumArray;
121    type Error = ();
122    fn parse_array(&self) -> Result<Self::Array, Self::Error> {
123        self.u8_array().ok_or(())
124    }
125}