1use std::fmt::{self, Display, Formatter};
23use std::str::FromStr;
24
25use amplify::confinement::{TinyOrdMap, TinyOrdSet};
26use amplify::{ByteArray, Bytes32};
27use baid58::{Baid58ParseError, Chunking, FromBaid58, ToBaid58, CHUNKING_32};
28use commit_verify::{CommitStrategy, CommitmentId};
29use rgb::{
30 AssignmentType, ExtensionType, GlobalStateType, SchemaId, SchemaTypeIndex, Script, SubSchema,
31 TransitionType, ValencyType,
32};
33use strict_encoding::{FieldName, TypeName};
34use strict_types::encoding::{
35 StrictDecode, StrictDeserialize, StrictEncode, StrictSerialize, StrictType,
36};
37
38use crate::interface::iface::IfaceId;
39use crate::interface::{Iface, VerNo};
40use crate::{ReservedBytes, LIB_NAME_RGB_STD};
41
42#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
46#[wrapper(Deref, BorrowSlice, Hex, Index, RangeOps)]
47#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
48#[strict_type(lib = LIB_NAME_RGB_STD)]
49#[cfg_attr(
50 feature = "serde",
51 derive(Serialize, Deserialize),
52 serde(crate = "serde_crate", transparent)
53)]
54pub struct ImplId(
55 #[from]
56 #[from([u8; 32])]
57 Bytes32,
58);
59
60impl ToBaid58<32> for ImplId {
61 const HRI: &'static str = "im";
62 const CHUNKING: Option<Chunking> = CHUNKING_32;
63 fn to_baid58_payload(&self) -> [u8; 32] { self.to_byte_array() }
64 fn to_baid58_string(&self) -> String { self.to_string() }
65}
66impl FromBaid58<32> for ImplId {}
67impl Display for ImplId {
68 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
69 if !f.alternate() {
70 f.write_str("urn:lnp-bp:im:")?;
71 }
72 if f.sign_minus() {
73 write!(f, "{:.2}", self.to_baid58())
74 } else {
75 write!(f, "{:#.2}", self.to_baid58())
76 }
77 }
78}
79impl FromStr for ImplId {
80 type Err = Baid58ParseError;
81 fn from_str(s: &str) -> Result<Self, Self::Err> {
82 Self::from_baid58_maybe_chunked_str(s.trim_start_matches("urn:lnp-bp:"), ':', '#')
83 }
84}
85impl ImplId {
86 pub fn to_mnemonic(&self) -> String { self.to_baid58().mnemonic() }
87}
88
89#[derive(Clone, Eq, PartialOrd, Ord, Debug)]
95#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
96#[strict_type(lib = LIB_NAME_RGB_STD)]
97#[cfg_attr(
98 feature = "serde",
99 derive(Serialize, Deserialize),
100 serde(crate = "serde_crate", rename_all = "camelCase")
101)]
102pub struct NamedField<T: SchemaTypeIndex> {
103 pub id: T,
104 pub name: FieldName,
105 pub reserved: ReservedBytes<0u8, 4usize>,
108}
109
110impl<T> PartialEq for NamedField<T>
111where T: SchemaTypeIndex
112{
113 fn eq(&self, other: &Self) -> bool { self.id == other.id || self.name == other.name }
114}
115
116impl<T: SchemaTypeIndex> NamedField<T> {
117 pub fn with(id: T, name: FieldName) -> NamedField<T> {
118 NamedField {
119 id,
120 name,
121 reserved: default!(),
122 }
123 }
124}
125
126#[derive(Clone, Eq, PartialOrd, Ord, Debug)]
131#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
132#[strict_type(lib = LIB_NAME_RGB_STD)]
133#[cfg_attr(
134 feature = "serde",
135 derive(Serialize, Deserialize),
136 serde(crate = "serde_crate", rename_all = "camelCase")
137)]
138pub struct NamedType<T: SchemaTypeIndex> {
139 pub id: T,
140 pub name: TypeName,
141 pub reserved: ReservedBytes<0, 4>,
143}
144
145impl<T> PartialEq for NamedType<T>
146where T: SchemaTypeIndex
147{
148 fn eq(&self, other: &Self) -> bool { self.id == other.id || self.name == other.name }
149}
150
151impl<T: SchemaTypeIndex> NamedType<T> {
152 pub fn with(id: T, name: TypeName) -> NamedType<T> {
153 NamedType {
154 id,
155 name,
156 reserved: default!(),
157 }
158 }
159}
160
161#[derive(Clone, Eq, PartialEq, Debug)]
162#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
163#[strict_type(lib = LIB_NAME_RGB_STD)]
164pub struct SchemaIfaces {
165 pub schema: SubSchema,
166 pub iimpls: TinyOrdMap<IfaceId, IfaceImpl>,
167}
168
169impl SchemaIfaces {
170 pub fn new(schema: SubSchema) -> Self {
171 SchemaIfaces {
172 schema,
173 iimpls: none!(),
174 }
175 }
176}
177
178#[derive(Clone, Eq, PartialEq, Debug)]
180#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
181#[strict_type(lib = LIB_NAME_RGB_STD)]
182#[cfg_attr(
183 feature = "serde",
184 derive(Serialize, Deserialize),
185 serde(crate = "serde_crate", rename_all = "camelCase")
186)]
187pub struct IfaceImpl {
188 pub version: VerNo,
189 pub schema_id: SchemaId,
190 pub iface_id: IfaceId,
191 pub global_state: TinyOrdSet<NamedField<GlobalStateType>>,
192 pub assignments: TinyOrdSet<NamedField<AssignmentType>>,
193 pub valencies: TinyOrdSet<NamedField<ValencyType>>,
194 pub transitions: TinyOrdSet<NamedType<TransitionType>>,
195 pub extensions: TinyOrdSet<NamedField<ExtensionType>>,
196 pub script: Script,
197}
198
199impl CommitStrategy for IfaceImpl {
200 type Strategy = commit_verify::strategies::Strict;
201}
202
203impl CommitmentId for IfaceImpl {
204 const TAG: [u8; 32] = *b"urn:lnpbp:rgb:ifaceimpl:v01#2303";
205 type Id = ImplId;
206}
207
208impl StrictSerialize for IfaceImpl {}
209impl StrictDeserialize for IfaceImpl {}
210
211impl IfaceImpl {
212 #[inline]
213 pub fn impl_id(&self) -> ImplId { self.commitment_id() }
214
215 pub fn global_type(&self, name: &FieldName) -> Option<GlobalStateType> {
216 self.global_state
217 .iter()
218 .find(|nt| &nt.name == name)
219 .map(|nt| nt.id)
220 }
221
222 pub fn assignments_type(&self, name: &FieldName) -> Option<AssignmentType> {
223 self.assignments
224 .iter()
225 .find(|nt| &nt.name == name)
226 .map(|nt| nt.id)
227 }
228
229 pub fn transition_type(&self, name: &TypeName) -> Option<TransitionType> {
230 self.transitions
231 .iter()
232 .find(|nt| &nt.name == name)
233 .map(|nt| nt.id)
234 }
235
236 pub fn global_name(&self, id: GlobalStateType) -> Option<&FieldName> {
237 self.global_state
238 .iter()
239 .find(|nt| nt.id == id)
240 .map(|nt| &nt.name)
241 }
242
243 pub fn assignment_name(&self, id: AssignmentType) -> Option<&FieldName> {
244 self.assignments
245 .iter()
246 .find(|nt| nt.id == id)
247 .map(|nt| &nt.name)
248 }
249
250 pub fn transition_name(&self, id: TransitionType) -> Option<&TypeName> {
251 self.transitions
252 .iter()
253 .find(|nt| nt.id == id)
254 .map(|nt| &nt.name)
255 }
256}
257
258#[derive(Clone, Eq, PartialEq, Debug)]
261#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
262#[strict_type(lib = LIB_NAME_RGB_STD)]
263#[cfg_attr(
264 feature = "serde",
265 derive(Serialize, Deserialize),
266 serde(crate = "serde_crate", rename_all = "camelCase")
267)]
268pub struct IfacePair {
269 pub iface: Iface,
270 pub iimpl: IfaceImpl,
271}
272
273impl IfacePair {
274 pub fn with(iface: Iface, iimpl: IfaceImpl) -> IfacePair { IfacePair { iface, iimpl } }
275
276 pub fn iface_id(&self) -> IfaceId { self.iface.iface_id() }
277 pub fn impl_id(&self) -> ImplId { self.iimpl.impl_id() }
278 pub fn global_type(&self, name: &FieldName) -> Option<GlobalStateType> {
279 self.iimpl.global_type(name)
280 }
281 pub fn assignments_type(&self, name: &FieldName) -> Option<AssignmentType> {
282 self.iimpl.assignments_type(name)
283 }
284 pub fn transition_type(&self, name: &TypeName) -> Option<TransitionType> {
285 self.iimpl.transition_type(name)
286 }
287}