1#![no_std]
10
11#[cfg(feature = "alloc")]
12extern crate alloc;
13#[cfg(feature = "alloc")]
14use alloc::{string::String, vec::Vec};
15
16pub mod format;
17pub mod view;
18
19pub use format::{
20 FINAL_SECTION_NAME, RAW_SECTION_NAME, RAW_SECTION_PREFIX, RAW_SPEC_FORMAT,
21 SpecSection, classify_section,
22};
23
24#[cfg(feature = "owned-model")]
25pub use thruput_spec::{
26 ContractArrayType, ContractEnumDef, ContractEnumVariant, ContractEventDef,
27 ContractExceptionType, ContractField, ContractMethodEffect,
28 ContractSignedTokenPreimage, ContractSpec, ContractSpecId,
29 ContractSpecInterface, ContractSpecMethod, ContractSpecString,
30 ContractStructDef, ContractType, ContractTypeDef, ContractTypeDefKind,
31 ContractTypeKind, ContractUnionCase, ContractUnionCaseKind,
32 ContractUnionCaseType, ContractUnionDef, ContractVectorType,
33};
34#[cfg(feature = "owned-model")]
35mod fragment;
36#[cfg(feature = "owned-model")]
37pub use fragment::*;
38pub use view::*;
39#[cfg(feature = "alloc")]
40use xdrs::VecM;
41
42mod thruput_xdr_types;
43
44pub trait ContractTypeSpec {
46 const TYPE_DEF: view::ContractTypeDefView<'static>;
48}
49
50#[diagnostic::on_unimplemented(
55 message = "`{Self}` is not a contract event",
56 label = "not a contract event",
57 note = "add `#[derive(Event)]` to `{Self}` — `emits(...)` in \
58 `#[contract(...)]` requires it"
59)]
60pub trait ContractEventSpec {
61 const EVENT_DEF: view::ContractEventDefView<'static>;
63
64 #[doc(hidden)]
67 const __THRUPUT_SPEC_ANCHOR_ROOT: fn() -> usize =
68 Self::__thruput_spec_anchor;
69
70 #[doc(hidden)]
72 #[cfg_attr(target_arch = "riscv32", inline(never))]
73 #[cfg_attr(
74 target_arch = "riscv32",
75 unsafe(link_section = "thruputspecanchortextv0")
76 )]
77 fn __thruput_spec_anchor() -> usize {
78 0
79 }
80}
81
82pub trait ContractTypeName {
84 const NAME: view::ContractSpecIdView<'static>;
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110pub struct ContractTypeInfo<'a> {
111 pub ty: view::ContractTypeView<'a>,
113}
114
115#[diagnostic::on_unimplemented(
118 message = "`{Self}` cannot appear in a contract signature",
119 label = "not a contract-spec type",
120 note = "annotate the defining type with `#[contract_type]` (error \
121 types: `#[contract_exception]`, events: `#[derive(Event)]`)"
122)]
123pub trait ContractTypeRefSpec {
124 const INFO: ContractTypeInfo<'static>;
128
129 const SIGNED_PREIMAGE: Option<&'static view::ContractTypeView<'static>> =
134 Some(&Self::INFO.ty);
135
136 #[doc(hidden)]
138 const __THRUPUT_SPEC_ANCHOR_ROOT: fn() -> usize =
139 Self::__thruput_spec_anchor;
140
141 #[doc(hidden)]
143 #[cfg_attr(target_arch = "riscv32", inline(never))]
144 #[cfg_attr(
145 target_arch = "riscv32",
146 unsafe(link_section = "thruputspecanchortextv0")
147 )]
148 fn __thruput_spec_anchor() -> usize {
149 0
150 }
151}
152
153#[doc(hidden)]
154#[inline(always)]
155pub fn mix_anchor_fn(current: usize, anchor: fn() -> usize) -> usize {
156 current ^ core::hint::black_box(anchor as usize)
157}
158
159impl ContractTypeRefSpec for () {
160 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
161 ty: view::ContractTypeView::Void,
162 };
163}
164
165impl ContractTypeRefSpec for bool {
166 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
167 ty: view::ContractTypeView::Bool,
168 };
169}
170
171impl ContractTypeRefSpec for u8 {
172 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
173 ty: view::ContractTypeView::U8,
174 };
175}
176
177impl ContractTypeRefSpec for u32 {
178 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
179 ty: view::ContractTypeView::U32,
180 };
181}
182
183impl ContractTypeRefSpec for i32 {
184 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
185 ty: view::ContractTypeView::I32,
186 };
187}
188
189impl ContractTypeRefSpec for u64 {
190 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
191 ty: view::ContractTypeView::U64,
192 };
193}
194
195impl ContractTypeRefSpec for i64 {
196 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
197 ty: view::ContractTypeView::I64,
198 };
199}
200
201impl ContractTypeRefSpec for u128 {
202 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
203 ty: view::ContractTypeView::U128,
204 };
205}
206
207impl ContractTypeRefSpec for i128 {
208 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
209 ty: view::ContractTypeView::I128,
210 };
211}
212
213impl ContractTypeRefSpec for str {
214 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
215 ty: view::ContractTypeView::String,
216 };
217}
218
219impl<T> ContractTypeRefSpec for [T]
228where
229 T: ContractTypeRefSpec,
230{
231 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
232 ty: view::ContractTypeView::Vector(view::ContractVectorTypeView {
233 element: &type_ref::<T>(),
234 max_len: u32::MAX,
235 }),
236 };
237
238 #[cfg_attr(target_arch = "riscv32", inline(never))]
239 #[cfg_attr(
240 target_arch = "riscv32",
241 unsafe(link_section = "thruputspecanchortextv0")
242 )]
243 fn __thruput_spec_anchor() -> usize {
244 mix_anchor_fn(
245 0,
246 <T as ContractTypeRefSpec>::__THRUPUT_SPEC_ANCHOR_ROOT,
247 )
248 }
249}
250
251impl ContractTypeRefSpec for &[u8] {
252 const INFO: ContractTypeInfo<'static> =
253 <[u8] as ContractTypeRefSpec>::INFO;
254}
255
256impl ContractTypeRefSpec for &str {
257 const INFO: ContractTypeInfo<'static> = <str as ContractTypeRefSpec>::INFO;
258}
259
260impl<const MAX: u32> ContractTypeRefSpec for xdr_common::StringM<MAX> {
261 const INFO: ContractTypeInfo<'static> = <str as ContractTypeRefSpec>::INFO;
262}
263
264impl<const MAX: usize> ContractTypeRefSpec for heapless::String<MAX> {
265 const INFO: ContractTypeInfo<'static> = <str as ContractTypeRefSpec>::INFO;
266}
267
268impl<const MAX: u32> ContractTypeRefSpec for xdr_common::BytesM<MAX> {
269 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
270 ty: view::ContractTypeView::Vector(view::ContractVectorTypeView {
271 element: &view::ContractTypeView::U8,
272 max_len: MAX,
273 }),
274 };
275}
276
277impl<T, const N: usize> ContractTypeRefSpec for heapless::Vec<T, N>
281where
282 T: ContractTypeRefSpec,
283{
284 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
285 ty: view::ContractTypeView::Vector(view::ContractVectorTypeView {
286 element: &type_ref::<T>(),
287 max_len: N as u32,
288 }),
289 };
290
291 #[cfg_attr(target_arch = "riscv32", inline(never))]
292 #[cfg_attr(
293 target_arch = "riscv32",
294 unsafe(link_section = "thruputspecanchortextv0")
295 )]
296 fn __thruput_spec_anchor() -> usize {
297 mix_anchor_fn(
298 0,
299 <T as ContractTypeRefSpec>::__THRUPUT_SPEC_ANCHOR_ROOT,
300 )
301 }
302}
303
304impl<T, const N: usize> ContractTypeRefSpec for [T; N]
305where
306 T: ContractTypeRefSpec,
307{
308 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
309 ty: view::ContractTypeView::Array(view::ContractArrayTypeView {
310 element: &type_ref::<T>(),
311 len: N as u32,
312 }),
313 };
314
315 #[cfg_attr(target_arch = "riscv32", inline(never))]
316 #[cfg_attr(
317 target_arch = "riscv32",
318 unsafe(link_section = "thruputspecanchortextv0")
319 )]
320 fn __thruput_spec_anchor() -> usize {
321 mix_anchor_fn(
322 0,
323 <T as ContractTypeRefSpec>::__THRUPUT_SPEC_ANCHOR_ROOT,
324 )
325 }
326}
327
328#[cfg(feature = "alloc")]
329impl ContractTypeRefSpec for String {
330 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
331 ty: view::ContractTypeView::String,
332 };
333}
334
335#[cfg(feature = "alloc")]
336impl<T> ContractTypeRefSpec for Vec<T>
337where
338 T: ContractTypeRefSpec,
339{
340 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
341 ty: view::ContractTypeView::Vector(view::ContractVectorTypeView {
342 element: &type_ref::<T>(),
343 max_len: u32::MAX,
344 }),
345 };
346
347 #[cfg_attr(target_arch = "riscv32", inline(never))]
348 #[cfg_attr(
349 target_arch = "riscv32",
350 unsafe(link_section = "thruputspecanchortextv0")
351 )]
352 fn __thruput_spec_anchor() -> usize {
353 mix_anchor_fn(
354 0,
355 <T as ContractTypeRefSpec>::__THRUPUT_SPEC_ANCHOR_ROOT,
356 )
357 }
358}
359
360#[cfg(feature = "alloc")]
361impl<T, const N: u32> ContractTypeRefSpec for VecM<T, N>
362where
363 T: ContractTypeRefSpec,
364{
365 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
366 ty: view::ContractTypeView::Vector(view::ContractVectorTypeView {
367 element: &type_ref::<T>(),
368 max_len: N,
369 }),
370 };
371
372 #[cfg_attr(target_arch = "riscv32", inline(never))]
373 #[cfg_attr(
374 target_arch = "riscv32",
375 unsafe(link_section = "thruputspecanchortextv0")
376 )]
377 fn __thruput_spec_anchor() -> usize {
378 mix_anchor_fn(
379 0,
380 <T as ContractTypeRefSpec>::__THRUPUT_SPEC_ANCHOR_ROOT,
381 )
382 }
383}
384
385impl<T> ContractTypeRefSpec for Option<T>
386where
387 T: ContractTypeRefSpec,
388{
389 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
390 ty: view::ContractTypeView::Option(&type_ref::<T>()),
391 };
392
393 #[cfg_attr(target_arch = "riscv32", inline(never))]
394 #[cfg_attr(
395 target_arch = "riscv32",
396 unsafe(link_section = "thruputspecanchortextv0")
397 )]
398 fn __thruput_spec_anchor() -> usize {
399 mix_anchor_fn(
400 0,
401 <T as ContractTypeRefSpec>::__THRUPUT_SPEC_ANCHOR_ROOT,
402 )
403 }
404}
405
406#[cfg(feature = "alloc")]
407impl<T> ContractTypeRefSpec for alloc::boxed::Box<T>
408where
409 T: ContractTypeRefSpec,
410{
411 const INFO: ContractTypeInfo<'static> = T::INFO;
412
413 #[cfg_attr(target_arch = "riscv32", inline(never))]
414 #[cfg_attr(
415 target_arch = "riscv32",
416 unsafe(link_section = "thruputspecanchortextv0")
417 )]
418 fn __thruput_spec_anchor() -> usize {
419 mix_anchor_fn(
420 0,
421 <T as ContractTypeRefSpec>::__THRUPUT_SPEC_ANCHOR_ROOT,
422 )
423 }
424}
425
426macro_rules! impl_tuple_type_ref_spec {
427 ($(($($name:ident),+)),+ $(,)?) => {
428 $(
429 impl<$($name),+> ContractTypeRefSpec for ($($name,)+)
430 where
431 $($name: ContractTypeRefSpec),+
432 {
433 const INFO: ContractTypeInfo<'static> = ContractTypeInfo {
434 ty: view::ContractTypeView::Tuple(&[$(type_ref::<$name>()),+]),
435 };
436
437 #[cfg_attr(target_arch = "riscv32", inline(never))]
438 #[cfg_attr(
439 target_arch = "riscv32",
440 unsafe(link_section = "thruputspecanchortextv0")
441 )]
442 fn __thruput_spec_anchor() -> usize {
443 let mut acc = 0usize;
444 $(acc = mix_anchor_fn(acc, <$name as ContractTypeRefSpec>::__THRUPUT_SPEC_ANCHOR_ROOT);)+
445 acc
446 }
447 }
448 )+
449 };
450}
451
452impl_tuple_type_ref_spec!(
453 (A),
454 (A, B),
455 (A, B, C),
456 (A, B, C, D),
457 (A, B, C, D, E),
458 (A, B, C, D, E, F),
459 (A, B, C, D, E, F, G),
460 (A, B, C, D, E, F, G, H),
461 (A, B, C, D, E, F, G, H, I),
462 (A, B, C, D, E, F, G, H, I, J),
463 (A, B, C, D, E, F, G, H, I, J, K),
464 (A, B, C, D, E, F, G, H, I, J, K, L),
465 (A, B, C, D, E, F, G, H, I, J, K, L, M),
466 (A, B, C, D, E, F, G, H, I, J, K, L, M, N),
467 (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O),
468 (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P),
469);
470
471pub const fn symbol<T: ContractTypeSpec>() -> view::ContractSpecIdView<'static>
476{
477 T::TYPE_DEF.symbol()
478}
479
480pub const fn type_ref<T: ContractTypeRefSpec + ?Sized>()
482-> view::ContractTypeView<'static> {
483 T::INFO.ty
484}