1#[cfg(test)]
2#[path = "tests/application.rs"]
3mod tests;
4
5use core::fmt::{self, Display, Formatter};
6use core::ops::Deref;
7use core::str::FromStr;
8#[cfg(feature = "borsh")]
9use std::io;
10
11#[cfg(feature = "borsh")]
12use borsh::{BorshDeserialize, BorshSerialize};
13use serde::de::{Error as SerdeError, Visitor};
14use serde::{Deserialize, Deserializer, Serialize, Serializer};
15use thiserror::Error as ThisError;
16use url::{ParseError, Url};
17
18use crate::blobs::BlobId;
19use crate::hash::{Hash, HashError};
20
21#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, Ord, PartialOrd)]
22#[cfg_attr(
23 feature = "borsh",
24 derive(borsh::BorshDeserialize, borsh::BorshSerialize)
25)]
26pub struct ApplicationId(Hash);
29
30impl From<[u8; 32]> for ApplicationId {
31 fn from(id: [u8; 32]) -> Self {
32 Self(id.into())
33 }
34}
35
36impl AsRef<[u8; 32]> for ApplicationId {
37 fn as_ref(&self) -> &[u8; 32] {
38 &self.0
39 }
40}
41
42impl Deref for ApplicationId {
43 type Target = [u8; 32];
44
45 fn deref(&self) -> &Self::Target {
46 &self.0
47 }
48}
49
50impl ApplicationId {
51 #[must_use]
52 pub fn as_str(&self) -> &str {
53 self.0.as_str()
54 }
55}
56
57impl Display for ApplicationId {
58 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
59 f.pad(self.as_str())
60 }
61}
62
63impl From<ApplicationId> for String {
64 fn from(id: ApplicationId) -> Self {
65 id.as_str().to_owned()
66 }
67}
68
69impl From<&ApplicationId> for String {
70 fn from(id: &ApplicationId) -> Self {
71 id.as_str().to_owned()
72 }
73}
74
75#[derive(Clone, Copy, Debug, ThisError)]
76#[error(transparent)]
77pub struct InvalidApplicationId(HashError);
78
79impl FromStr for ApplicationId {
80 type Err = InvalidApplicationId;
81
82 fn from_str(s: &str) -> Result<Self, Self::Err> {
83 Ok(Self(s.parse().map_err(InvalidApplicationId)?))
84 }
85}
86
87#[derive(Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
92pub struct SignerId(Box<str>);
93
94impl SignerId {
95 pub fn new(s: impl Into<Box<str>>) -> Result<Self, InvalidSignerId> {
101 let s = s.into();
102 if s.is_empty() {
103 return Err(InvalidSignerId::Empty);
104 }
105 Ok(Self(s))
106 }
107
108 #[must_use]
110 pub fn as_str(&self) -> &str {
111 &self.0
112 }
113}
114
115impl Deref for SignerId {
116 type Target = str;
117
118 fn deref(&self) -> &Self::Target {
119 &self.0
120 }
121}
122
123impl AsRef<str> for SignerId {
124 fn as_ref(&self) -> &str {
125 &self.0
126 }
127}
128
129impl Display for SignerId {
130 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
131 f.pad(&self.0)
132 }
133}
134
135impl From<SignerId> for String {
136 fn from(id: SignerId) -> Self {
137 id.0.into_string()
138 }
139}
140
141impl From<&SignerId> for String {
142 fn from(id: &SignerId) -> Self {
143 id.0.to_string()
144 }
145}
146
147#[derive(Clone, Copy, Debug, ThisError)]
149#[non_exhaustive]
150pub enum InvalidSignerId {
151 #[error("signerId cannot be empty")]
153 Empty,
154}
155
156impl FromStr for SignerId {
157 type Err = InvalidSignerId;
158
159 fn from_str(s: &str) -> Result<Self, Self::Err> {
160 Self::new(s)
161 }
162}
163
164impl Serialize for SignerId {
165 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
166 serializer.serialize_str(&self.0)
167 }
168}
169
170impl<'de> Deserialize<'de> for SignerId {
171 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
172 struct SignerIdVisitor;
173
174 impl Visitor<'_> for SignerIdVisitor {
175 type Value = SignerId;
176
177 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
178 formatter.write_str("a non-empty signer identifier string")
179 }
180
181 fn visit_str<E: SerdeError>(self, v: &str) -> Result<Self::Value, E> {
182 SignerId::new(v).map_err(E::custom)
183 }
184 }
185
186 deserializer.deserialize_str(SignerIdVisitor)
187 }
188}
189
190#[cfg(feature = "borsh")]
191impl BorshSerialize for SignerId {
192 fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
193 let bytes = self.0.as_bytes();
195 let len = bytes.len() as u32;
196 BorshSerialize::serialize(&len, writer)?;
197 writer.write_all(bytes)
198 }
199}
200
201#[cfg(feature = "borsh")]
202impl BorshDeserialize for SignerId {
203 fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
204 let len = u32::deserialize_reader(reader)? as usize;
205 let mut bytes = vec![0u8; len];
206 reader.read_exact(&mut bytes)?;
207
208 let s =
209 String::from_utf8(bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
210 SignerId::new(s).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
211 }
212}
213
214#[derive(Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
219pub struct AppKey {
220 app_id: Box<str>,
222 signer_id: SignerId,
224}
225
226impl AppKey {
227 pub fn new(app_id: impl Into<Box<str>>, signer_id: SignerId) -> Result<Self, InvalidAppKey> {
234 let app_id = app_id.into();
235 if app_id.is_empty() {
236 return Err(InvalidAppKey::EmptyAppId);
237 }
238 if app_id.contains(':') {
239 return Err(InvalidAppKey::ColonInAppId);
240 }
241 Ok(Self { app_id, signer_id })
242 }
243
244 #[must_use]
246 pub fn app_id(&self) -> &str {
247 &self.app_id
248 }
249
250 #[must_use]
252 pub fn signer_id(&self) -> &SignerId {
253 &self.signer_id
254 }
255}
256
257impl Display for AppKey {
258 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
259 write!(f, "{}:{}", self.app_id, self.signer_id)
260 }
261}
262
263impl From<AppKey> for String {
264 fn from(key: AppKey) -> Self {
265 key.to_string()
266 }
267}
268
269impl From<&AppKey> for String {
270 fn from(key: &AppKey) -> Self {
271 key.to_string()
272 }
273}
274
275#[derive(Clone, Debug, ThisError)]
277#[non_exhaustive]
278pub enum InvalidAppKey {
279 #[error("appId cannot be empty")]
281 EmptyAppId,
282
283 #[error("appId cannot contain ':' (colon is used as separator in serialized format)")]
285 ColonInAppId,
286
287 #[error("invalid signerId: {0}")]
289 InvalidSignerId(#[from] InvalidSignerId),
290
291 #[error("invalid AppKey format: expected 'appId:signerId', got '{0}'")]
293 InvalidFormat(String),
294}
295
296impl FromStr for AppKey {
297 type Err = InvalidAppKey;
298
299 fn from_str(s: &str) -> Result<Self, Self::Err> {
300 let separator_pos = s
303 .find(':')
304 .ok_or_else(|| InvalidAppKey::InvalidFormat(s.to_owned()))?;
305
306 let app_id = &s[..separator_pos];
307 let signer_id_str = &s[separator_pos + 1..];
308
309 let signer_id = SignerId::new(signer_id_str)?;
310 Self::new(app_id, signer_id)
311 }
312}
313
314impl Serialize for AppKey {
315 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
316 serializer.serialize_str(&self.to_string())
317 }
318}
319
320impl<'de> Deserialize<'de> for AppKey {
321 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
322 struct AppKeyVisitor;
323
324 impl Visitor<'_> for AppKeyVisitor {
325 type Value = AppKey;
326
327 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
328 formatter.write_str("a string in format 'appId:signerId'")
329 }
330
331 fn visit_str<E: SerdeError>(self, v: &str) -> Result<Self::Value, E> {
332 AppKey::from_str(v).map_err(E::custom)
333 }
334 }
335
336 deserializer.deserialize_str(AppKeyVisitor)
337 }
338}
339
340#[cfg(feature = "borsh")]
341impl BorshSerialize for AppKey {
342 fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
343 let app_id_bytes = self.app_id.as_bytes();
345 let app_id_len = app_id_bytes.len() as u32;
346 BorshSerialize::serialize(&app_id_len, writer)?;
347 writer.write_all(app_id_bytes)?;
348
349 BorshSerialize::serialize(&self.signer_id, writer)
351 }
352}
353
354#[cfg(feature = "borsh")]
355impl BorshDeserialize for AppKey {
356 fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
357 let app_id_len = u32::deserialize_reader(reader)? as usize;
359 let mut app_id_bytes = vec![0u8; app_id_len];
360 reader.read_exact(&mut app_id_bytes)?;
361 let app_id = String::from_utf8(app_id_bytes)
362 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?
363 .into_boxed_str();
364
365 let signer_id = SignerId::deserialize_reader(reader)?;
367
368 AppKey::new(app_id, signer_id).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
369 }
370}
371
372#[derive(Clone, Debug, Deserialize, Serialize)]
373pub struct ApplicationSource(Url);
374
375impl FromStr for ApplicationSource {
376 type Err = ParseError;
377
378 fn from_str(s: &str) -> Result<Self, Self::Err> {
379 s.parse().map(Self)
380 }
381}
382
383impl From<Url> for ApplicationSource {
384 fn from(value: Url) -> Self {
385 Self(value)
386 }
387}
388
389impl From<ApplicationSource> for Url {
390 fn from(value: ApplicationSource) -> Self {
391 value.0
392 }
393}
394
395impl Display for ApplicationSource {
396 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
397 Display::fmt(&self.0, f)
398 }
399}
400
401#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
402#[cfg_attr(
403 feature = "borsh",
404 derive(borsh::BorshDeserialize, borsh::BorshSerialize)
405)]
406pub struct ApplicationBlob {
407 pub bytecode: BlobId,
408 pub compiled: BlobId,
409}
410
411#[derive(Clone, Debug, Deserialize, Serialize)]
412#[non_exhaustive]
413pub struct Application {
414 pub id: ApplicationId,
415 pub blob: ApplicationBlob,
416 pub size: u64,
417 pub source: ApplicationSource,
418 pub metadata: Vec<u8>,
419}
420
421impl Application {
422 #[must_use]
423 pub const fn new(
424 id: ApplicationId,
425 blob: ApplicationBlob,
426 size: u64,
427 source: ApplicationSource,
428 metadata: Vec<u8>,
429 ) -> Self {
430 Self {
431 id,
432 blob,
433 size,
434 source,
435 metadata,
436 }
437 }
438}