homestar_invocation/authority/
issuer.rs1use crate::{Error, Unit};
4use const_format::formatcp;
5#[cfg(feature = "diesel")]
6use diesel::{
7 backend::Backend,
8 deserialize::{self, FromSql, FromSqlRow},
9 expression::AsExpression,
10 serialize::{self, IsNull, Output, ToSql},
11 sql_types::Text,
12 sqlite::Sqlite,
13};
14use libipld::{serde::from_ipld, Ipld};
15use schemars::{
16 gen::SchemaGenerator,
17 schema::{InstanceType, Metadata, Schema, SchemaObject, SingleOrVec},
18 JsonSchema,
19};
20use serde::{Deserialize, Serialize};
21use std::{borrow::Cow, fmt, module_path, str::FromStr};
22use ucan::ipld::Principle as Principal;
23
24#[cfg(feature = "diesel")]
31#[cfg_attr(docsrs, doc(cfg(feature = "diesel")))]
32#[derive(Clone, Debug, Deserialize, Serialize, AsExpression, FromSqlRow, PartialEq)]
33#[diesel(sql_type = Text)]
34#[repr(transparent)]
35pub struct Issuer(Principal);
36
37#[cfg(not(feature = "diesel"))]
44#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
45#[repr(transparent)]
46pub struct Issuer(Principal);
47
48impl Issuer {
49 pub fn new(principal: Principal) -> Self {
51 Issuer(principal)
52 }
53}
54
55impl fmt::Display for Issuer {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 let did_as_string = self.0.to_string();
58 write!(f, "{did_as_string}")
59 }
60}
61
62impl From<Issuer> for Ipld {
63 fn from(issuer: Issuer) -> Self {
64 let principal = issuer.0.to_string();
65 Ipld::String(principal)
66 }
67}
68
69impl TryFrom<Ipld> for Issuer {
70 type Error = Error<Unit>;
71
72 fn try_from(ipld: Ipld) -> Result<Self, Self::Error> {
73 let s = from_ipld::<String>(ipld)?;
74 Ok(Issuer(Principal::from_str(&s)?))
75 }
76}
77
78#[cfg(feature = "diesel")]
79#[cfg_attr(docsrs, doc(cfg(feature = "diesel")))]
80impl ToSql<Text, Sqlite> for Issuer {
81 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
82 out.set_value(self.0.to_string());
83 Ok(IsNull::No)
84 }
85}
86
87#[cfg(feature = "diesel")]
88#[cfg_attr(docsrs, doc(cfg(feature = "diesel")))]
89impl<DB> FromSql<Text, DB> for Issuer
90where
91 DB: Backend,
92 String: FromSql<Text, DB>,
93{
94 fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
95 let s = String::from_sql(bytes)?;
96 Ok(Issuer(Principal::from_str(&s)?))
97 }
98}
99
100impl JsonSchema for Issuer {
101 fn schema_name() -> String {
102 "iss".to_owned()
103 }
104
105 fn schema_id() -> Cow<'static, str> {
106 Cow::Borrowed(formatcp!("{}::Issuer", module_path!()))
107 }
108
109 fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
110 let schema = SchemaObject {
111 instance_type: Some(SingleOrVec::Single(InstanceType::String.into())),
112 metadata: Some(Box::new(Metadata {
113 title: Some("Issuer".to_string()),
114 description: Some("Principal that issued the receipt".to_string()),
115 ..Default::default()
116 })),
117 ..Default::default()
118 };
119 schema.into()
120 }
121}
122
123#[cfg(test)]
124mod test {
125 use super::*;
126
127 #[test]
128 fn ser_de() {
129 let issuer = Issuer::new(Principal::from_str("did:example:alice").unwrap());
130 let ser = serde_json::to_string(&issuer).unwrap();
131 let de = serde_json::from_str(&ser).unwrap();
132
133 assert_eq!(issuer, de);
134 }
135}