1use crate::document::property_names;
2
3use crate::identity::TimestampMillis;
4use crate::prelude::{BlockHeight, CoreBlockHeight, Revision};
5
6use crate::ProtocolError;
7
8use crate::document::serialization_traits::{
9 DocumentCborMethodsV0, DocumentPlatformValueMethodsV0,
10};
11use crate::document::v0::DocumentV0;
12use crate::version::PlatformVersion;
13use ciborium::Value as CborValue;
14use integer_encoding::VarIntWriter;
15use platform_value::btreemap_extensions::BTreeValueRemoveFromMapHelper;
16use platform_value::{Identifier, Value};
17use serde::{Deserialize, Serialize};
18use std::collections::BTreeMap;
19use std::convert::{TryFrom, TryInto};
20
21#[cfg(feature = "cbor")]
22#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
23pub struct DocumentForCbor {
24 #[serde(rename = "$id")]
26 pub id: [u8; 32],
27
28 #[serde(flatten)]
30 pub properties: BTreeMap<String, CborValue>,
31
32 #[serde(rename = "$ownerId")]
34 pub owner_id: [u8; 32],
35
36 #[serde(rename = "$revision")]
38 pub revision: Option<Revision>,
39
40 #[serde(rename = "$createdAt")]
41 pub created_at: Option<TimestampMillis>,
42 #[serde(rename = "$updatedAt")]
43 pub updated_at: Option<TimestampMillis>,
44 #[serde(rename = "$transferredAt")]
45 pub transferred_at: Option<TimestampMillis>,
46
47 #[serde(rename = "$createdAtBlockHeight")]
48 pub created_at_block_height: Option<BlockHeight>,
49 #[serde(rename = "$updatedAtBlockHeight")]
50 pub updated_at_block_height: Option<BlockHeight>,
51 #[serde(rename = "$transferredAtBlockHeight")]
52 pub transferred_at_block_height: Option<BlockHeight>,
53
54 #[serde(rename = "$createdAtCoreBlockHeight")]
55 pub created_at_core_block_height: Option<CoreBlockHeight>,
56 #[serde(rename = "$updatedAtCoreBlockHeight")]
57 pub updated_at_core_block_height: Option<CoreBlockHeight>,
58 #[serde(rename = "$transferredAtCoreBlockHeight")]
59 pub transferred_at_core_block_height: Option<CoreBlockHeight>,
60
61 #[serde(rename = "$creatorId")]
62 pub creator_id: Option<Identifier>,
63}
64
65#[cfg(feature = "cbor")]
66impl TryFrom<DocumentV0> for DocumentForCbor {
67 type Error = ProtocolError;
68
69 fn try_from(value: DocumentV0) -> Result<Self, Self::Error> {
70 let DocumentV0 {
71 id,
72 properties,
73 owner_id,
74 revision,
75 created_at,
76 updated_at,
77 transferred_at,
78 created_at_block_height,
79 updated_at_block_height,
80 transferred_at_block_height,
81 created_at_core_block_height,
82 updated_at_core_block_height,
83 transferred_at_core_block_height,
84 creator_id,
85 } = value;
86 Ok(DocumentForCbor {
87 id: id.to_buffer(),
88 properties: Value::convert_to_cbor_map(properties)
89 .map_err(ProtocolError::ValueError)?,
90 owner_id: owner_id.to_buffer(),
91 revision,
92 created_at,
93 updated_at,
94 transferred_at,
95 created_at_block_height,
96 updated_at_block_height,
97 transferred_at_block_height,
98 created_at_core_block_height,
99 updated_at_core_block_height,
100 transferred_at_core_block_height,
101 creator_id,
102 })
103 }
104}
105
106impl DocumentV0 {
107 fn from_map(
110 mut document_map: BTreeMap<String, Value>,
111 document_id: Option<[u8; 32]>,
112 owner_id: Option<[u8; 32]>,
113 ) -> Result<Self, ProtocolError> {
114 let owner_id = match owner_id {
115 None => document_map
116 .remove_hash256_bytes(property_names::OWNER_ID)
117 .map_err(ProtocolError::ValueError)?,
118 Some(owner_id) => owner_id,
119 };
120
121 let id = match document_id {
122 None => document_map
123 .remove_hash256_bytes(property_names::ID)
124 .map_err(ProtocolError::ValueError)?,
125 Some(document_id) => document_id,
126 };
127
128 let revision = document_map.remove_optional_integer(property_names::REVISION)?;
129
130 let created_at = document_map.remove_optional_integer(property_names::CREATED_AT)?;
131 let updated_at = document_map.remove_optional_integer(property_names::UPDATED_AT)?;
132 let transferred_at =
133 document_map.remove_optional_integer(property_names::TRANSFERRED_AT)?;
134 let created_at_block_height =
135 document_map.remove_optional_integer(property_names::CREATED_AT_BLOCK_HEIGHT)?;
136 let updated_at_block_height =
137 document_map.remove_optional_integer(property_names::UPDATED_AT_BLOCK_HEIGHT)?;
138 let transferred_at_block_height =
139 document_map.remove_optional_integer(property_names::TRANSFERRED_AT_BLOCK_HEIGHT)?;
140 let created_at_core_block_height =
141 document_map.remove_optional_integer(property_names::CREATED_AT_CORE_BLOCK_HEIGHT)?;
142 let updated_at_core_block_height =
143 document_map.remove_optional_integer(property_names::UPDATED_AT_CORE_BLOCK_HEIGHT)?;
144 let transferred_at_core_block_height = document_map
145 .remove_optional_integer(property_names::TRANSFERRED_AT_CORE_BLOCK_HEIGHT)?;
146
147 let creator_id = document_map
148 .remove_optional_identifier(property_names::CREATOR_ID)
149 .map_err(ProtocolError::ValueError)?;
150
151 Ok(DocumentV0 {
153 properties: document_map,
154 owner_id: Identifier::new(owner_id),
155 id: Identifier::new(id),
156 revision,
157 created_at,
158 updated_at,
159 transferred_at,
160 created_at_block_height,
161 updated_at_block_height,
162 transferred_at_block_height,
163 created_at_core_block_height,
164 updated_at_core_block_height,
165 transferred_at_core_block_height,
166 creator_id,
167 })
168 }
169}
170
171impl DocumentCborMethodsV0 for DocumentV0 {
172 fn from_cbor(
175 document_cbor: &[u8],
176 document_id: Option<[u8; 32]>,
177 owner_id: Option<[u8; 32]>,
178 _platform_version: &PlatformVersion,
179 ) -> Result<Self, ProtocolError> {
180 let document_cbor_map: BTreeMap<String, CborValue> =
183 ciborium::de::from_reader(document_cbor).map_err(|_| {
184 ProtocolError::InvalidCBOR(
185 "unable to decode document for document call".to_string(),
186 )
187 })?;
188 let document_map: BTreeMap<String, Value> =
189 Value::convert_from_cbor_map(document_cbor_map).map_err(ProtocolError::ValueError)?;
190 Self::from_map(document_map, document_id, owner_id)
191 }
192
193 fn to_cbor_value(&self) -> Result<CborValue, ProtocolError> {
194 self.to_object()
195 .map(|v| v.try_into().map_err(ProtocolError::ValueError))?
196 }
197
198 fn to_cbor(&self) -> Result<Vec<u8>, ProtocolError> {
200 let mut buffer: Vec<u8> = Vec::new();
201 buffer.write_varint(0).map_err(|_| {
202 ProtocolError::EncodingError("error writing protocol version".to_string())
203 })?;
204 let cbor_document = DocumentForCbor::try_from(self.clone())?;
205 ciborium::ser::into_writer(&cbor_document, &mut buffer).map_err(|_| {
206 ProtocolError::EncodingError("unable to serialize into cbor".to_string())
207 })?;
208 Ok(buffer)
209 }
210}