dpp_domain/disclosure/audience.rs
1//! [`Audience`] — who is asking for passport data.
2
3use serde::{Deserialize, Serialize};
4
5use super::class::{DISCLOSURE_ORDER, Disclosure, disclosure_key};
6
7/// Who is asking for passport data.
8///
9/// Regulation (EU) 2023/1542 Art. 77(2) names three audiences and assigns each
10/// a set of Annex XIII data points:
11///
12/// | Audience | Annex XIII |
13/// |---|---|
14/// | (a) general public | 1 |
15/// | (b) notified bodies, market surveillance authorities, the Commission | 2 and 3 |
16/// | (c) persons with a legitimate interest | 2 and 4 |
17///
18/// **This is a lattice, not a ranking.** Point 3 (conformity test reports) is
19/// authority-only; point 4 (individual-item use history) is
20/// legitimate-interest-only. Neither audience contains the other, so no integer
21/// ordering can express the assignment: any `>=` comparison necessarily either
22/// hands authorities the individual-item data Art. 77(2)(b) withholds, or hides
23/// point-2 data from someone entitled to it.
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
25#[serde(rename_all = "snake_case")]
26#[non_exhaustive]
27pub enum Audience {
28 /// Anyone, with no credential. Art. 77(2)(a).
29 Public,
30 /// A repairer, remanufacturer, second-life operator or recycler holding a
31 /// credential that proves the interest. Art. 77(2)(c).
32 LegitimateInterest,
33 /// Notified body, market surveillance authority, customs, or the
34 /// Commission. Art. 77(2)(b).
35 Authority,
36}
37
38impl Audience {
39 /// The disclosure classes this audience may see, in Annex XIII order.
40 #[must_use]
41 pub fn disclosure_set(self) -> Vec<Disclosure> {
42 DISCLOSURE_ORDER
43 .iter()
44 .copied()
45 .filter(|d| self.may_see(*d))
46 .collect()
47 }
48
49 /// The [`disclosure_key`] for this audience's classes — the name under which
50 /// a view served to it is signed and audited.
51 ///
52 /// Two audiences with the same class set would share a key, and that is
53 /// correct: the artefact describes the data it covers, not who asked.
54 #[must_use]
55 pub fn disclosure_key(self) -> String {
56 disclosure_key(&self.disclosure_set())
57 }
58
59 /// Whether this audience may see a field of class `disclosure`.
60 ///
61 /// The whole Art. 77(2) assignment, in one table.
62 #[must_use]
63 pub const fn may_see(self, disclosure: Disclosure) -> bool {
64 matches!(
65 (self, disclosure),
66 (Self::Public, Disclosure::Public)
67 | (
68 Self::LegitimateInterest,
69 Disclosure::Public | Disclosure::Restricted | Disclosure::Individual
70 )
71 | (
72 Self::Authority,
73 Disclosure::Public | Disclosure::Restricted | Disclosure::Conformity
74 )
75 )
76 }
77}