ssi_vc/v2/syntax/
presentation.rs1use std::{borrow::Cow, collections::BTreeMap, hash::Hash};
2
3use crate::syntax::{not_null, value_or_array, IdOr, IdentifiedObject};
4use crate::v2::{Context, Credential};
5use iref::{Uri, UriBuf};
6use rdf_types::VocabularyMut;
7use serde::{Deserialize, Serialize};
8use ssi_claims_core::{ClaimsValidity, ValidateClaims};
9use ssi_json_ld::{JsonLdError, JsonLdNodeObject, JsonLdObject, JsonLdTypes, Loader};
10use ssi_rdf::{Interpretation, LdEnvironment, LinkedDataResource, LinkedDataSubject};
11
12use super::JsonCredential;
13
14pub use crate::v1::syntax::{
15 JsonPresentationTypes, PresentationType, VERIFIABLE_PRESENTATION_TYPE,
16};
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
20#[serde(bound(
21 serialize = "C: serde::Serialize",
22 deserialize = "C: serde::Deserialize<'de>"
23))]
24pub struct JsonPresentation<C = JsonCredential> {
25 #[serde(rename = "@context")]
27 pub context: Context,
28
29 #[serde(
31 default,
32 deserialize_with = "not_null",
33 skip_serializing_if = "Option::is_none"
34 )]
35 pub id: Option<UriBuf>,
36
37 #[serde(rename = "type")]
39 pub types: JsonPresentationTypes,
40
41 #[serde(rename = "holder")]
43 #[serde(
44 with = "value_or_array",
45 default,
46 skip_serializing_if = "Vec::is_empty"
47 )]
48 pub holders: Vec<IdOr<IdentifiedObject>>,
49
50 #[serde(rename = "verifiableCredential")]
52 #[serde(
53 with = "value_or_array",
54 default,
55 skip_serializing_if = "Vec::is_empty"
56 )]
57 pub verifiable_credentials: Vec<C>,
58
59 #[serde(flatten)]
60 pub additional_properties: BTreeMap<String, json_syntax::Value>,
61}
62
63impl Default for JsonPresentation {
64 fn default() -> Self {
65 Self {
66 context: Context::default(),
67 id: None,
68 types: JsonPresentationTypes::default(),
69 verifiable_credentials: Vec::new(),
70 holders: Vec::new(),
71 additional_properties: BTreeMap::new(),
72 }
73 }
74}
75
76impl<C> JsonPresentation<C> {
77 pub fn new(
78 id: Option<UriBuf>,
79 holders: Vec<IdOr<IdentifiedObject>>,
80 verifiable_credentials: Vec<C>,
81 ) -> Self {
82 Self {
83 context: Context::default(),
84 id,
85 types: JsonPresentationTypes::default(),
86 holders,
87 verifiable_credentials,
88 additional_properties: BTreeMap::new(),
89 }
90 }
91}
92
93impl<C> JsonLdObject for JsonPresentation<C> {
94 fn json_ld_context(&self) -> Option<Cow<ssi_json_ld::syntax::Context>> {
95 Some(Cow::Borrowed(self.context.as_ref()))
96 }
97}
98
99impl<C> JsonLdNodeObject for JsonPresentation<C> {
100 fn json_ld_type(&self) -> JsonLdTypes {
101 self.types.to_json_ld_types()
102 }
103}
104
105impl<C, E, P> ValidateClaims<E, P> for JsonPresentation<C> {
106 fn validate_claims(&self, _: &E, _: &P) -> ClaimsValidity {
107 Ok(())
108 }
109}
110
111impl<C: Credential> crate::MaybeIdentified for JsonPresentation<C> {
112 fn id(&self) -> Option<&Uri> {
113 self.id.as_deref()
114 }
115}
116
117impl<C: Credential> crate::v2::Presentation for JsonPresentation<C> {
118 type Credential = C;
120
121 type Holder = IdOr<IdentifiedObject>;
122
123 fn additional_types(&self) -> &[String] {
125 self.types.additional_types()
126 }
127
128 fn verifiable_credentials(&self) -> &[Self::Credential] {
129 &self.verifiable_credentials
130 }
131
132 fn holders(&self) -> &[Self::Holder] {
133 &self.holders
134 }
135}
136
137impl<C> ssi_json_ld::Expandable for JsonPresentation<C>
138where
139 C: Serialize,
140{
141 type Error = JsonLdError;
142
143 type Expanded<I, V>
144 = ssi_json_ld::ExpandedDocument<V::Iri, V::BlankId>
145 where
146 I: Interpretation,
147 V: VocabularyMut,
148 V::Iri: LinkedDataResource<I, V> + LinkedDataSubject<I, V>,
149 V::BlankId: LinkedDataResource<I, V> + LinkedDataSubject<I, V>;
150
151 async fn expand_with<I, V>(
152 &self,
153 ld: &mut LdEnvironment<V, I>,
154 loader: &impl Loader,
155 ) -> Result<Self::Expanded<I, V>, Self::Error>
156 where
157 I: Interpretation,
158 V: VocabularyMut,
159 V::Iri: Clone + Eq + Hash + LinkedDataResource<I, V> + LinkedDataSubject<I, V>,
160 V::BlankId: Clone + Eq + Hash + LinkedDataResource<I, V> + LinkedDataSubject<I, V>,
161 {
162 let json = ssi_json_ld::CompactJsonLd(json_syntax::to_value(self).unwrap());
163 json.expand_with(ld, loader).await
164 }
165}