liminal_protocol/
credential.rs1use alloc::vec::Vec;
14
15pub const WIRE_PASS_V1_TAG: u8 = 1;
17pub const LYS_PASS_V1_TAG: u8 = 2;
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub enum WireCredential<'a> {
23 PassV1(&'a [u8]),
25 LysPass(&'a [u8]),
27}
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31pub enum CredentialKindError {
32 Empty,
34 UnknownTag(u8),
36 EmptyLysPass,
38}
39
40impl core::fmt::Display for CredentialKindError {
41 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42 match self {
43 Self::Empty => formatter.write_str("credential is empty"),
44 Self::UnknownTag(tag) => write!(formatter, "credential tag {tag} is unknown"),
45 Self::EmptyLysPass => formatter.write_str("lys pass record carries no pass"),
46 }
47 }
48}
49
50impl core::error::Error for CredentialKindError {}
51
52impl<'a> WireCredential<'a> {
53 pub const fn classify(bytes: &'a [u8]) -> Result<Self, CredentialKindError> {
58 match bytes {
59 [] => Err(CredentialKindError::Empty),
60 [WIRE_PASS_V1_TAG, ..] => Ok(Self::PassV1(bytes)),
61 [LYS_PASS_V1_TAG] => Err(CredentialKindError::EmptyLysPass),
62 [LYS_PASS_V1_TAG, pass @ ..] => Ok(Self::LysPass(pass)),
63 [tag, ..] => Err(CredentialKindError::UnknownTag(*tag)),
64 }
65 }
66
67 #[must_use]
69 pub fn lys_record(pass: &[u8]) -> Vec<u8> {
70 let mut record = Vec::with_capacity(pass.len() + 1);
71 record.push(LYS_PASS_V1_TAG);
72 record.extend_from_slice(pass);
73 record
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::{CredentialKindError, LYS_PASS_V1_TAG, WIRE_PASS_V1_TAG, WireCredential};
80
81 #[test]
82 fn a_v1_record_keeps_its_tag_for_the_pass_checker() {
83 let bytes = [WIRE_PASS_V1_TAG, 7, 8];
84 assert_eq!(
85 WireCredential::classify(&bytes),
86 Ok(WireCredential::PassV1(&bytes))
87 );
88 }
89
90 #[test]
91 fn a_lys_record_hands_over_the_pass_without_its_tag() {
92 let record = WireCredential::lys_record(b"issued-by-lys");
93 assert_eq!(record[0], LYS_PASS_V1_TAG);
94 assert_eq!(
95 WireCredential::classify(&record),
96 Ok(WireCredential::LysPass(b"issued-by-lys"))
97 );
98 }
99
100 #[test]
101 fn bytes_outside_both_records_are_refused_by_name() {
102 assert_eq!(
103 WireCredential::classify(&[]),
104 Err(CredentialKindError::Empty)
105 );
106 assert_eq!(
107 WireCredential::classify(&[LYS_PASS_V1_TAG]),
108 Err(CredentialKindError::EmptyLysPass)
109 );
110 assert_eq!(
111 WireCredential::classify(&[9, 1]),
112 Err(CredentialKindError::UnknownTag(9))
113 );
114 }
115}