1use crate::capabilities::CapabilitiesDocument;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub enum Profile {
19 RegistryCore,
21 RegistryDiscovery,
23 RegistryFederated,
25 RegistryReceipts,
28 Consumer,
30}
31
32impl Profile {
33 pub fn as_str(self) -> &'static str {
36 match self {
37 Profile::RegistryCore => "acdp-registry-core",
38 Profile::RegistryDiscovery => "acdp-registry-discovery",
39 Profile::RegistryFederated => "acdp-registry-federated",
40 Profile::RegistryReceipts => "acdp-registry-receipts",
41 Profile::Consumer => "acdp-consumer",
42 }
43 }
44}
45
46pub const CLAIMED: &[Profile] = &[Profile::Consumer];
52
53impl CapabilitiesDocument {
54 pub fn claims_profile(&self, profile: Profile) -> bool {
56 self.profiles.iter().any(|p| p == profile.as_str())
57 }
58
59 pub fn supports_required(
63 &self,
64 required: &[Profile],
65 ) -> Result<(), acdp_primitives::error::AcdpError> {
66 for p in required {
67 if !self.claims_profile(*p) {
68 return Err(acdp_primitives::error::AcdpError::SchemaViolation(format!(
69 "registry does not advertise required profile '{}'",
70 p.as_str()
71 )));
72 }
73 }
74 Ok(())
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use crate::capabilities::Limits;
82
83 fn caps_with(profiles: Vec<&str>) -> CapabilitiesDocument {
84 CapabilitiesDocument {
85 acdp_version: "0.1.0".into(),
86 registry_did: "did:web:r.example.com".into(),
87 supported_signature_algorithms: vec!["ed25519".into()],
88 supported_did_methods: vec!["did:web".into()],
89 profiles: profiles.into_iter().map(String::from).collect(),
90 limits: Limits {
91 max_payload_bytes: 1_048_576,
92 max_embedded_bytes: 65_536,
93 idempotency_key_ttl_seconds: None,
94 },
95 read_authentication_methods: vec![],
96 anonymous_public_reads: true,
97 supports_idempotency_key: false,
98 extensions: Default::default(),
99 }
100 }
101
102 #[test]
103 fn claimed_profile_matches() {
104 let caps = caps_with(vec!["acdp-registry-core", "acdp-registry-discovery"]);
105 assert!(caps.claims_profile(Profile::RegistryCore));
106 assert!(caps.claims_profile(Profile::RegistryDiscovery));
107 assert!(!caps.claims_profile(Profile::RegistryFederated));
108 }
109
110 #[test]
111 fn supports_required_returns_first_missing() {
112 let caps = caps_with(vec!["acdp-registry-core"]);
113 caps.supports_required(&[Profile::RegistryCore]).unwrap();
114 let err = caps
115 .supports_required(&[Profile::RegistryCore, Profile::RegistryFederated])
116 .unwrap_err();
117 match err {
118 acdp_primitives::error::AcdpError::SchemaViolation(msg) => {
119 assert!(msg.contains("acdp-registry-federated"));
120 }
121 other => panic!("got {other:?}"),
122 }
123 }
124
125 #[test]
126 fn claimed_includes_consumer() {
127 assert!(CLAIMED.contains(&Profile::Consumer));
128 }
129}