1#![allow(clippy::new_ret_no_self)]
16
17use crate::{
18 serde_hex,
19 utils::{
20 deserialize_from_byte_str,
21 serialize_as_byte_str,
22 trim_extra_whitespace,
23 },
24};
25#[cfg(not(feature = "std"))]
26use alloc::{
27 collections::BTreeMap,
28 format,
29 string::String,
30 vec,
31 vec::Vec,
32};
33use core::{
34 fmt::Display,
35 marker::PhantomData,
36};
37use scale_info::{
38 form::{
39 Form,
40 MetaForm,
41 PortableForm,
42 },
43 meta_type,
44 IntoPortable,
45 Registry,
46 TypeInfo,
47};
48use schemars::JsonSchema;
49use serde::{
50 de::DeserializeOwned,
51 Deserialize,
52 Serialize,
53};
54#[cfg(feature = "std")]
55use std::{
56 collections::BTreeMap,
57 hash::Hash,
58};
59
60#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
62#[serde(bound(
63 serialize = "F::Type: Serialize, F::String: Serialize",
64 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
65))]
66pub struct ContractSpec<F: Form = MetaForm>
67where
68 TypeSpec<F>: Default,
69{
70 constructors: Vec<ConstructorSpec<F>>,
72 messages: Vec<MessageSpec<F>>,
74 events: Vec<EventSpec<F>>,
76 docs: Vec<F::String>,
78 lang_error: TypeSpec<F>,
80 environment: EnvironmentSpec<F>,
82}
83
84impl IntoPortable for ContractSpec {
85 type Output = ContractSpec<PortableForm>;
86
87 fn into_portable(self, registry: &mut Registry) -> Self::Output {
88 ContractSpec {
89 constructors: self
90 .constructors
91 .into_iter()
92 .map(|constructor| constructor.into_portable(registry))
93 .collect::<Vec<_>>(),
94 messages: self
95 .messages
96 .into_iter()
97 .map(|msg| msg.into_portable(registry))
98 .collect::<Vec<_>>(),
99 events: self
100 .events
101 .into_iter()
102 .map(|event| event.into_portable(registry))
103 .collect::<Vec<_>>(),
104 docs: registry.map_into_portable(self.docs),
105 lang_error: self.lang_error.into_portable(registry),
106 environment: self.environment.into_portable(registry),
107 }
108 }
109}
110
111impl<F> ContractSpec<F>
112where
113 F: Form,
114 TypeSpec<F>: Default,
115{
116 pub fn constructors(&self) -> &[ConstructorSpec<F>] {
118 &self.constructors
119 }
120
121 pub fn messages(&self) -> &[MessageSpec<F>] {
123 &self.messages
124 }
125
126 pub fn events(&self) -> &[EventSpec<F>] {
128 &self.events
129 }
130
131 pub fn docs(&self) -> &[F::String] {
133 &self.docs
134 }
135
136 pub fn lang_error(&self) -> &TypeSpec<F> {
138 &self.lang_error
139 }
140 pub fn environment(&self) -> &EnvironmentSpec<F> {
142 &self.environment
143 }
144}
145
146pub enum Valid {}
148pub enum Invalid {}
150
151#[must_use]
152pub struct ContractSpecBuilder<F, S = Invalid>
153where
154 F: Form,
155 TypeSpec<F>: Default,
156{
157 spec: ContractSpec<F>,
159 marker: PhantomData<fn() -> S>,
161}
162
163impl<F> ContractSpecBuilder<F, Invalid>
164where
165 F: Form,
166 TypeSpec<F>: Default,
167{
168 pub fn constructors<C>(self, constructors: C) -> ContractSpecBuilder<F, Valid>
170 where
171 C: IntoIterator<Item = ConstructorSpec<F>>,
172 {
173 debug_assert!(self.spec.constructors.is_empty());
174 ContractSpecBuilder {
175 spec: ContractSpec {
176 constructors: constructors.into_iter().collect::<Vec<_>>(),
177 ..self.spec
178 },
179 marker: Default::default(),
180 }
181 }
182}
183
184impl<F, S> ContractSpecBuilder<F, S>
185where
186 F: Form,
187 TypeSpec<F>: Default,
188{
189 pub fn messages<M>(self, messages: M) -> Self
191 where
192 M: IntoIterator<Item = MessageSpec<F>>,
193 {
194 debug_assert!(self.spec.messages.is_empty());
195 Self {
196 spec: ContractSpec {
197 messages: messages.into_iter().collect::<Vec<_>>(),
198 ..self.spec
199 },
200 ..self
201 }
202 }
203
204 pub fn events<E>(self, events: E) -> Self
206 where
207 E: IntoIterator<Item = EventSpec<F>>,
208 {
209 debug_assert!(self.spec.events.is_empty());
210 Self {
211 spec: ContractSpec {
212 events: events.into_iter().collect::<Vec<_>>(),
213 ..self.spec
214 },
215 ..self
216 }
217 }
218
219 pub fn docs<D>(self, docs: D) -> Self
221 where
222 D: IntoIterator<Item = <F as Form>::String>,
223 {
224 debug_assert!(self.spec.docs.is_empty());
225 Self {
226 spec: ContractSpec {
227 docs: docs.into_iter().collect::<Vec<_>>(),
228 ..self.spec
229 },
230 ..self
231 }
232 }
233
234 pub fn lang_error(self, lang_error: TypeSpec<F>) -> Self {
236 Self {
237 spec: ContractSpec {
238 lang_error,
239 ..self.spec
240 },
241 ..self
242 }
243 }
244
245 pub fn environment(self, environment: EnvironmentSpec<F>) -> Self {
247 Self {
248 spec: ContractSpec {
249 environment,
250 ..self.spec
251 },
252 ..self
253 }
254 }
255}
256
257impl<S> ContractSpecBuilder<MetaForm, S> {
258 pub fn collect_events(self) -> Self {
260 self.events(crate::collect_events())
261 }
262}
263
264impl<F> ContractSpecBuilder<F, Valid>
265where
266 F: Form,
267 F::String: Display,
268 TypeSpec<F>: Default,
269{
270 #[allow(clippy::arithmetic_side_effects)] pub fn done(self) -> ContractSpec<F> {
273 assert!(
274 !self.spec.constructors.is_empty(),
275 "must have at least one constructor"
276 );
277 assert!(
278 !self.spec.messages.is_empty(),
279 "must have at least one message"
280 );
281 assert!(
282 self.spec.constructors.iter().filter(|c| c.default).count() < 2,
283 "only one default constructor is allowed"
284 );
285 assert!(
286 self.spec.messages.iter().filter(|m| m.default).count() < 2,
287 "only one default message is allowed"
288 );
289
290 let max_topics = self.spec.environment.max_event_topics;
291 let events_exceeding_max_topics_limit = self
292 .spec
293 .events
294 .iter()
295 .filter_map(|e| {
296 let signature_topic = if e.signature_topic.is_some() { 1 } else { 0 };
297 let topics_count =
298 signature_topic + e.args.iter().filter(|a| a.indexed).count();
299 if topics_count > max_topics {
300 Some(format!(
301 "`{}::{}` ({} topics)",
302 e.module_path, e.label, topics_count
303 ))
304 } else {
305 None
306 }
307 })
308 .collect::<Vec<_>>();
309 assert!(
310 events_exceeding_max_topics_limit.is_empty(),
311 "maximum of {max_topics} event topics exceeded: {}",
312 events_exceeding_max_topics_limit.join(", ")
313 );
314
315 let mut signature_topics: BTreeMap<Vec<u8>, Vec<String>> = BTreeMap::new();
316 for e in self.spec.events.iter() {
317 if let Some(signature_topic) = &e.signature_topic {
318 signature_topics
319 .entry(signature_topic.bytes.clone())
320 .or_default()
321 .push(format!("`{}::{}`", e.module_path, e.label));
322 }
323 }
324 let signature_topic_collisions = signature_topics
325 .iter()
326 .filter_map(|(_, topics)| {
327 if topics.len() > 1 {
328 Some(format!(
329 "event signature topic collision: {}",
330 topics.join(", ")
331 ))
332 } else {
333 None
334 }
335 })
336 .collect::<Vec<_>>();
337 assert!(
338 signature_topic_collisions.is_empty(),
339 "{}",
340 signature_topic_collisions.join("\n")
341 );
342
343 self.spec
344 }
345}
346
347impl<F> ContractSpec<F>
348where
349 F: Form,
350 TypeSpec<F>: Default,
351 EnvironmentSpec<F>: Default,
352{
353 pub fn new() -> ContractSpecBuilder<F, Invalid> {
355 ContractSpecBuilder {
356 spec: Self {
357 constructors: Vec::new(),
358 messages: Vec::new(),
359 events: Vec::new(),
360 docs: Vec::new(),
361 lang_error: Default::default(),
362 environment: Default::default(),
363 },
364 marker: PhantomData,
365 }
366 }
367}
368
369#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
371#[serde(bound(
372 serialize = "F::Type: Serialize, F::String: Serialize",
373 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned",
374))]
375#[serde(rename_all = "camelCase")]
376pub struct ConstructorSpec<F: Form = MetaForm> {
377 pub label: F::String,
382 pub selector: Selector,
384 pub payable: bool,
386 pub args: Vec<MessageParamSpec<F>>,
388 pub return_type: ReturnTypeSpec<F>,
390 pub docs: Vec<F::String>,
392 default: bool,
394}
395
396impl IntoPortable for ConstructorSpec {
397 type Output = ConstructorSpec<PortableForm>;
398
399 fn into_portable(self, registry: &mut Registry) -> Self::Output {
400 ConstructorSpec {
401 label: self.label.to_string(),
402 selector: self.selector,
403 payable: self.payable,
404 args: self
405 .args
406 .into_iter()
407 .map(|arg| arg.into_portable(registry))
408 .collect::<Vec<_>>(),
409 return_type: self.return_type.into_portable(registry),
410 docs: self.docs.into_iter().map(|s| s.into()).collect(),
411 default: self.default,
412 }
413 }
414}
415
416impl<F> ConstructorSpec<F>
417where
418 F: Form,
419{
420 pub fn label(&self) -> &F::String {
425 &self.label
426 }
427
428 pub fn selector(&self) -> &Selector {
430 &self.selector
431 }
432
433 pub fn payable(&self) -> bool {
435 self.payable
436 }
437
438 pub fn args(&self) -> &[MessageParamSpec<F>] {
440 &self.args
441 }
442
443 pub fn return_type(&self) -> &ReturnTypeSpec<F> {
445 &self.return_type
446 }
447
448 pub fn docs(&self) -> &[F::String] {
450 &self.docs
451 }
452
453 pub fn default(&self) -> bool {
454 self.default
455 }
456}
457
458#[allow(clippy::type_complexity)]
466#[must_use]
467pub struct ConstructorSpecBuilder<F: Form, Selector, IsPayable, Returns> {
468 spec: ConstructorSpec<F>,
469 marker: PhantomData<fn() -> (Selector, IsPayable, Returns)>,
470}
471
472impl<F> ConstructorSpec<F>
473where
474 F: Form,
475 TypeSpec<F>: Default,
476{
477 pub fn from_label(
479 label: <F as Form>::String,
480 ) -> ConstructorSpecBuilder<
481 F,
482 Missing<state::Selector>,
483 Missing<state::IsPayable>,
484 Missing<state::Returns>,
485 > {
486 ConstructorSpecBuilder {
487 spec: Self {
488 label,
489 selector: Selector::default(),
490 payable: Default::default(),
491 args: Vec::new(),
492 return_type: ReturnTypeSpec::new(TypeSpec::default()),
493 docs: Vec::new(),
494 default: false,
495 },
496 marker: PhantomData,
497 }
498 }
499}
500
501impl<F, P, R> ConstructorSpecBuilder<F, Missing<state::Selector>, P, R>
502where
503 F: Form,
504{
505 pub fn selector(
507 self,
508 selector: [u8; 4],
509 ) -> ConstructorSpecBuilder<F, state::Selector, P, R> {
510 ConstructorSpecBuilder {
511 spec: ConstructorSpec {
512 selector: selector.into(),
513 ..self.spec
514 },
515 marker: PhantomData,
516 }
517 }
518}
519
520impl<F, S, R> ConstructorSpecBuilder<F, S, Missing<state::IsPayable>, R>
521where
522 F: Form,
523{
524 pub fn payable(
526 self,
527 is_payable: bool,
528 ) -> ConstructorSpecBuilder<F, S, state::IsPayable, R> {
529 ConstructorSpecBuilder {
530 spec: ConstructorSpec {
531 payable: is_payable,
532 ..self.spec
533 },
534 marker: PhantomData,
535 }
536 }
537}
538
539impl<F, S, P> ConstructorSpecBuilder<F, S, P, Missing<state::Returns>>
540where
541 F: Form,
542{
543 pub fn returns(
545 self,
546 return_type: ReturnTypeSpec<F>,
547 ) -> ConstructorSpecBuilder<F, S, P, state::Returns> {
548 ConstructorSpecBuilder {
549 spec: ConstructorSpec {
550 return_type,
551 ..self.spec
552 },
553 marker: PhantomData,
554 }
555 }
556}
557
558impl<F, S, P, R> ConstructorSpecBuilder<F, S, P, R>
559where
560 F: Form,
561{
562 pub fn args<A>(self, args: A) -> Self
564 where
565 A: IntoIterator<Item = MessageParamSpec<F>>,
566 {
567 let mut this = self;
568 debug_assert!(this.spec.args.is_empty());
569 this.spec.args = args.into_iter().collect::<Vec<_>>();
570 this
571 }
572
573 pub fn docs<'a, D>(self, docs: D) -> Self
575 where
576 D: IntoIterator<Item = &'a str>,
577 F::String: From<&'a str>,
578 {
579 let mut this = self;
580 debug_assert!(this.spec.docs.is_empty());
581 this.spec.docs = docs
582 .into_iter()
583 .map(|s| trim_extra_whitespace(s).into())
584 .collect::<Vec<_>>();
585 this
586 }
587
588 pub fn default(self, default: bool) -> Self {
590 ConstructorSpecBuilder {
591 spec: ConstructorSpec {
592 default,
593 ..self.spec
594 },
595 marker: PhantomData,
596 }
597 }
598}
599
600impl<F> ConstructorSpecBuilder<F, state::Selector, state::IsPayable, state::Returns>
601where
602 F: Form,
603{
604 pub fn done(self) -> ConstructorSpec<F> {
606 self.spec
607 }
608}
609
610#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
612#[serde(bound(
613 serialize = "F::Type: Serialize, F::String: Serialize",
614 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
615))]
616#[serde(rename_all = "camelCase")]
617pub struct MessageSpec<F: Form = MetaForm> {
618 label: F::String,
623 selector: Selector,
625 mutates: bool,
627 payable: bool,
629 args: Vec<MessageParamSpec<F>>,
631 return_type: ReturnTypeSpec<F>,
633 docs: Vec<F::String>,
635 default: bool,
637}
638
639pub struct Missing<S>(PhantomData<fn() -> S>);
642
643mod state {
644 pub struct Selector;
649 pub struct Mutates;
651 pub struct IsPayable;
653 pub struct Returns;
655 pub struct AccountId;
657 pub struct Balance;
659 pub struct Hash;
661 pub struct Timestamp;
663 pub struct BlockNumber;
665 pub struct ChainExtension;
667 pub struct MaxEventTopics;
669 pub struct BufferSize;
671}
672
673impl<F> MessageSpec<F>
674where
675 F: Form,
676 TypeSpec<F>: Default,
677{
678 pub fn from_label(
680 label: <F as Form>::String,
681 ) -> MessageSpecBuilder<
682 F,
683 Missing<state::Selector>,
684 Missing<state::Mutates>,
685 Missing<state::IsPayable>,
686 Missing<state::Returns>,
687 > {
688 MessageSpecBuilder {
689 spec: Self {
690 label,
691 selector: Selector::default(),
692 mutates: false,
693 payable: false,
694 args: Vec::new(),
695 return_type: ReturnTypeSpec::new(TypeSpec::default()),
696 docs: Vec::new(),
697 default: false,
698 },
699 marker: PhantomData,
700 }
701 }
702}
703
704impl<F> MessageSpec<F>
705where
706 F: Form,
707{
708 pub fn label(&self) -> &F::String {
713 &self.label
714 }
715
716 pub fn selector(&self) -> &Selector {
718 &self.selector
719 }
720
721 pub fn mutates(&self) -> bool {
723 self.mutates
724 }
725
726 pub fn payable(&self) -> bool {
728 self.payable
729 }
730
731 pub fn args(&self) -> &[MessageParamSpec<F>] {
733 &self.args
734 }
735
736 pub fn return_type(&self) -> &ReturnTypeSpec<F> {
738 &self.return_type
739 }
740
741 pub fn docs(&self) -> &[F::String] {
743 &self.docs
744 }
745
746 pub fn default(&self) -> bool {
747 self.default
748 }
749}
750
751#[allow(clippy::type_complexity)]
759#[must_use]
760pub struct MessageSpecBuilder<F, Selector, Mutates, IsPayable, Returns>
761where
762 F: Form,
763{
764 spec: MessageSpec<F>,
765 marker: PhantomData<fn() -> (Selector, Mutates, IsPayable, Returns)>,
766}
767
768impl<F, M, P, R> MessageSpecBuilder<F, Missing<state::Selector>, M, P, R>
769where
770 F: Form,
771{
772 pub fn selector(
774 self,
775 selector: [u8; 4],
776 ) -> MessageSpecBuilder<F, state::Selector, M, P, R> {
777 MessageSpecBuilder {
778 spec: MessageSpec {
779 selector: selector.into(),
780 ..self.spec
781 },
782 marker: PhantomData,
783 }
784 }
785}
786
787impl<F, S, P, R> MessageSpecBuilder<F, S, Missing<state::Mutates>, P, R>
788where
789 F: Form,
790{
791 pub fn mutates(
794 self,
795 mutates: bool,
796 ) -> MessageSpecBuilder<F, S, state::Mutates, P, R> {
797 MessageSpecBuilder {
798 spec: MessageSpec {
799 mutates,
800 ..self.spec
801 },
802 marker: PhantomData,
803 }
804 }
805}
806
807impl<F, S, M, R> MessageSpecBuilder<F, S, M, Missing<state::IsPayable>, R>
808where
809 F: Form,
810{
811 pub fn payable(
813 self,
814 is_payable: bool,
815 ) -> MessageSpecBuilder<F, S, M, state::IsPayable, R> {
816 MessageSpecBuilder {
817 spec: MessageSpec {
818 payable: is_payable,
819 ..self.spec
820 },
821 marker: PhantomData,
822 }
823 }
824}
825
826impl<F, M, S, P> MessageSpecBuilder<F, S, M, P, Missing<state::Returns>>
827where
828 F: Form,
829{
830 pub fn returns(
832 self,
833 return_type: ReturnTypeSpec<F>,
834 ) -> MessageSpecBuilder<F, S, M, P, state::Returns> {
835 MessageSpecBuilder {
836 spec: MessageSpec {
837 return_type,
838 ..self.spec
839 },
840 marker: PhantomData,
841 }
842 }
843}
844
845impl<F, S, M, P, R> MessageSpecBuilder<F, S, M, P, R>
846where
847 F: Form,
848{
849 pub fn args<A>(self, args: A) -> Self
851 where
852 A: IntoIterator<Item = MessageParamSpec<F>>,
853 {
854 let mut this = self;
855 debug_assert!(this.spec.args.is_empty());
856 this.spec.args = args.into_iter().collect::<Vec<_>>();
857 this
858 }
859
860 pub fn docs<D>(self, docs: D) -> Self
862 where
863 D: IntoIterator<Item = <F as Form>::String>,
864 {
865 let mut this = self;
866 debug_assert!(this.spec.docs.is_empty());
867 this.spec.docs = docs.into_iter().collect::<Vec<_>>();
868 this
869 }
870
871 pub fn default(self, default: bool) -> Self {
873 MessageSpecBuilder {
874 spec: MessageSpec {
875 default,
876 ..self.spec
877 },
878 marker: PhantomData,
879 }
880 }
881}
882
883impl<F>
884 MessageSpecBuilder<
885 F,
886 state::Selector,
887 state::Mutates,
888 state::IsPayable,
889 state::Returns,
890 >
891where
892 F: Form,
893{
894 pub fn done(self) -> MessageSpec<F> {
896 self.spec
897 }
898}
899
900impl IntoPortable for MessageSpec {
901 type Output = MessageSpec<PortableForm>;
902
903 fn into_portable(self, registry: &mut Registry) -> Self::Output {
904 MessageSpec {
905 label: self.label.to_string(),
906 selector: self.selector,
907 mutates: self.mutates,
908 payable: self.payable,
909 default: self.default,
910 args: self
911 .args
912 .into_iter()
913 .map(|arg| arg.into_portable(registry))
914 .collect::<Vec<_>>(),
915 return_type: self.return_type.into_portable(registry),
916 docs: self.docs.into_iter().map(|s| s.into()).collect(),
917 }
918 }
919}
920
921#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
923#[serde(bound(
924 serialize = "F::Type: Serialize, F::String: Serialize",
925 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
926))]
927pub struct EventSpec<F: Form = MetaForm> {
928 label: F::String,
930 module_path: F::String,
932 signature_topic: Option<SignatureTopic>,
934 args: Vec<EventParamSpec<F>>,
936 docs: Vec<F::String>,
938}
939
940#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
942#[serde(transparent)]
943pub struct SignatureTopic {
944 #[serde(
945 serialize_with = "serialize_as_byte_str",
946 deserialize_with = "deserialize_from_byte_str"
947 )]
948 bytes: Vec<u8>,
949}
950
951impl<T> From<T> for SignatureTopic
952where
953 T: AsRef<[u8]>,
954{
955 fn from(bytes: T) -> Self {
956 SignatureTopic {
957 bytes: bytes.as_ref().to_vec(),
958 }
959 }
960}
961
962impl SignatureTopic {
963 pub fn as_bytes(&self) -> &[u8] {
965 &self.bytes
966 }
967}
968
969#[must_use]
971pub struct EventSpecBuilder<F>
972where
973 F: Form,
974{
975 spec: EventSpec<F>,
976}
977
978impl<F> EventSpecBuilder<F>
979where
980 F: Form,
981{
982 pub fn module_path<'a>(self, path: &'a str) -> Self
984 where
985 F::String: From<&'a str>,
986 {
987 let mut this = self;
988 this.spec.module_path = path.into();
989 this
990 }
991
992 pub fn args<A>(self, args: A) -> Self
994 where
995 A: IntoIterator<Item = EventParamSpec<F>>,
996 {
997 let mut this = self;
998 debug_assert!(this.spec.args.is_empty());
999 this.spec.args = args.into_iter().collect::<Vec<_>>();
1000 this
1001 }
1002
1003 pub fn signature_topic<T>(self, topic: Option<T>) -> Self
1005 where
1006 T: AsRef<[u8]>,
1007 {
1008 let mut this = self;
1009 debug_assert!(this.spec.signature_topic.is_none());
1010 this.spec.signature_topic = topic.as_ref().map(SignatureTopic::from);
1011 this
1012 }
1013
1014 pub fn docs<'a, D>(self, docs: D) -> Self
1016 where
1017 D: IntoIterator<Item = &'a str>,
1018 F::String: From<&'a str>,
1019 {
1020 let mut this = self;
1021 debug_assert!(this.spec.docs.is_empty());
1022 this.spec.docs = docs
1023 .into_iter()
1024 .map(|s| trim_extra_whitespace(s).into())
1025 .collect::<Vec<_>>();
1026 this
1027 }
1028
1029 pub fn done(self) -> EventSpec<F> {
1031 self.spec
1032 }
1033}
1034
1035impl IntoPortable for EventSpec {
1036 type Output = EventSpec<PortableForm>;
1037
1038 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1039 EventSpec {
1040 label: self.label.to_string(),
1041 module_path: self.module_path.to_string(),
1042 signature_topic: self.signature_topic,
1043 args: self
1044 .args
1045 .into_iter()
1046 .map(|arg| arg.into_portable(registry))
1047 .collect::<Vec<_>>(),
1048 docs: self.docs.into_iter().map(|s| s.into()).collect(),
1049 }
1050 }
1051}
1052
1053impl<F> EventSpec<F>
1054where
1055 F: Form,
1056 F::String: Default,
1057{
1058 pub fn new(label: <F as Form>::String) -> EventSpecBuilder<F> {
1060 EventSpecBuilder {
1061 spec: Self {
1062 label,
1063 module_path: Default::default(),
1064 signature_topic: None,
1065 args: Vec::new(),
1066 docs: Vec::new(),
1067 },
1068 }
1069 }
1070}
1071
1072impl<F> EventSpec<F>
1073where
1074 F: Form,
1075{
1076 pub fn label(&self) -> &F::String {
1078 &self.label
1079 }
1080
1081 pub fn args(&self) -> &[EventParamSpec<F>] {
1083 &self.args
1084 }
1085
1086 pub fn signature_topic(&self) -> Option<&SignatureTopic> {
1088 self.signature_topic.as_ref()
1089 }
1090
1091 pub fn docs(&self) -> &[F::String] {
1093 &self.docs
1094 }
1095}
1096
1097#[cfg_attr(feature = "std", derive(Hash))]
1099#[derive(Debug, Default, PartialEq, Eq, derive_more::From, JsonSchema)]
1100pub struct Selector(#[schemars(with = "String")] [u8; 4]);
1101
1102impl serde::Serialize for Selector {
1103 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1104 where
1105 S: serde::Serializer,
1106 {
1107 serde_hex::serialize(&self.0, serializer)
1108 }
1109}
1110
1111impl<'de> serde::Deserialize<'de> for Selector {
1112 fn deserialize<D>(d: D) -> Result<Self, D::Error>
1113 where
1114 D: serde::Deserializer<'de>,
1115 {
1116 let mut arr = [0; 4];
1117 serde_hex::deserialize_check_len(d, serde_hex::ExpectedLen::Exact(&mut arr[..]))?;
1118 Ok(arr.into())
1119 }
1120}
1121
1122impl Selector {
1123 pub fn new<T>(bytes: T) -> Self
1125 where
1126 T: Into<[u8; 4]>,
1127 {
1128 Self(bytes.into())
1129 }
1130
1131 pub fn to_bytes(&self) -> &[u8] {
1133 &self.0
1134 }
1135}
1136
1137pub type DisplayName<F> = scale_info::Path<F>;
1155
1156#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1174#[serde(bound(
1175 serialize = "F::Type: Serialize, F::String: Serialize",
1176 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1177))]
1178#[serde(rename_all = "camelCase")]
1179pub struct TypeSpec<F: Form = MetaForm> {
1180 #[serde(rename = "type")]
1182 ty: F::Type,
1183 display_name: DisplayName<F>,
1185}
1186
1187impl Default for TypeSpec<MetaForm> {
1188 fn default() -> Self {
1189 TypeSpec::of_type::<()>()
1190 }
1191}
1192
1193impl Default for TypeSpec<PortableForm> {
1194 fn default() -> Self {
1195 Self {
1196 ty: u32::default().into(),
1197 display_name: Default::default(),
1198 }
1199 }
1200}
1201
1202impl IntoPortable for TypeSpec {
1203 type Output = TypeSpec<PortableForm>;
1204
1205 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1206 TypeSpec {
1207 ty: registry.register_type(&self.ty),
1208 display_name: self.display_name.into_portable(registry),
1209 }
1210 }
1211}
1212
1213impl TypeSpec {
1214 pub fn with_name_str<T>(display_name: &'static str) -> Self
1226 where
1227 T: TypeInfo + 'static,
1228 {
1229 Self::with_name_segs::<T, _>(display_name.split("::"))
1230 }
1231
1232 pub fn with_name_segs<T, S>(segments: S) -> Self
1245 where
1246 T: TypeInfo + 'static,
1247 S: IntoIterator<Item = &'static str>,
1248 {
1249 Self {
1250 ty: meta_type::<T>(),
1251 display_name: DisplayName::from_segments(segments)
1252 .unwrap_or_else(|err| panic!("display name is invalid: {err:?}")),
1253 }
1254 }
1255
1256 pub fn of_type<T>() -> Self
1264 where
1265 T: TypeInfo + 'static,
1266 {
1267 Self {
1268 ty: meta_type::<T>(),
1269 display_name: DisplayName::default(),
1270 }
1271 }
1272}
1273
1274impl<F> TypeSpec<F>
1275where
1276 F: Form,
1277{
1278 pub fn ty(&self) -> &F::Type {
1280 &self.ty
1281 }
1282
1283 pub fn display_name(&self) -> &DisplayName<F> {
1285 &self.display_name
1286 }
1287
1288 pub fn new(ty: <F as Form>::Type, display_name: DisplayName<F>) -> Self {
1290 Self { ty, display_name }
1291 }
1292}
1293
1294#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1296#[serde(bound(
1297 serialize = "F::Type: Serialize, F::String: Serialize",
1298 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1299))]
1300pub struct EventParamSpec<F: Form = MetaForm> {
1301 label: F::String,
1303 indexed: bool,
1305 #[serde(rename = "type")]
1307 ty: TypeSpec<F>,
1308 docs: Vec<F::String>,
1310}
1311
1312impl IntoPortable for EventParamSpec {
1313 type Output = EventParamSpec<PortableForm>;
1314
1315 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1316 EventParamSpec {
1317 label: self.label.to_string(),
1318 indexed: self.indexed,
1319 ty: self.ty.into_portable(registry),
1320 docs: self.docs.into_iter().map(|s| s.into()).collect(),
1321 }
1322 }
1323}
1324
1325impl<F> EventParamSpec<F>
1326where
1327 F: Form,
1328 TypeSpec<F>: Default,
1329{
1330 pub fn new(label: F::String) -> EventParamSpecBuilder<F> {
1332 EventParamSpecBuilder {
1333 spec: Self {
1334 label,
1335 indexed: false,
1337 ty: Default::default(),
1339 docs: vec![],
1341 },
1342 }
1343 }
1344 pub fn label(&self) -> &F::String {
1346 &self.label
1347 }
1348
1349 pub fn indexed(&self) -> bool {
1351 self.indexed
1352 }
1353
1354 pub fn ty(&self) -> &TypeSpec<F> {
1356 &self.ty
1357 }
1358
1359 pub fn docs(&self) -> &[F::String] {
1361 &self.docs
1362 }
1363}
1364
1365#[must_use]
1367pub struct EventParamSpecBuilder<F>
1368where
1369 F: Form,
1370{
1371 spec: EventParamSpec<F>,
1373}
1374
1375impl<F> EventParamSpecBuilder<F>
1376where
1377 F: Form,
1378{
1379 pub fn of_type(self, spec: TypeSpec<F>) -> Self {
1381 let mut this = self;
1382 this.spec.ty = spec;
1383 this
1384 }
1385
1386 pub fn indexed(self, is_indexed: bool) -> Self {
1388 let mut this = self;
1389 this.spec.indexed = is_indexed;
1390 this
1391 }
1392
1393 pub fn docs<'a, D>(self, docs: D) -> Self
1395 where
1396 D: IntoIterator<Item = &'a str>,
1397 F::String: From<&'a str>,
1398 {
1399 debug_assert!(self.spec.docs.is_empty());
1400 Self {
1401 spec: EventParamSpec {
1402 docs: docs
1403 .into_iter()
1404 .map(|s| trim_extra_whitespace(s).into())
1405 .collect::<Vec<_>>(),
1406 ..self.spec
1407 },
1408 }
1409 }
1410
1411 pub fn done(self) -> EventParamSpec<F> {
1413 self.spec
1414 }
1415}
1416
1417#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1419#[serde(transparent)]
1420#[serde(bound(
1421 serialize = "F::Type: Serialize, F::String: Serialize",
1422 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1423))]
1424#[must_use]
1425pub struct ReturnTypeSpec<F: Form = MetaForm> {
1426 #[serde(rename = "type")]
1427 ret_type: TypeSpec<F>,
1428}
1429
1430impl IntoPortable for ReturnTypeSpec {
1431 type Output = ReturnTypeSpec<PortableForm>;
1432
1433 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1434 ReturnTypeSpec {
1435 ret_type: self.ret_type.into_portable(registry),
1436 }
1437 }
1438}
1439
1440impl<F> ReturnTypeSpec<F>
1441where
1442 F: Form,
1443 TypeSpec<F>: Default,
1444{
1445 pub fn new<T>(ty: T) -> Self
1454 where
1455 T: Into<TypeSpec<F>>,
1456 {
1457 Self {
1458 ret_type: ty.into(),
1459 }
1460 }
1461
1462 pub fn ret_type(&self) -> &TypeSpec<F> {
1464 &self.ret_type
1465 }
1466}
1467
1468#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1470#[serde(bound(
1471 serialize = "F::Type: Serialize, F::String: Serialize",
1472 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1473))]
1474pub struct MessageParamSpec<F: Form = MetaForm> {
1475 label: F::String,
1477 #[serde(rename = "type")]
1479 ty: TypeSpec<F>,
1480}
1481
1482impl IntoPortable for MessageParamSpec {
1483 type Output = MessageParamSpec<PortableForm>;
1484
1485 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1486 MessageParamSpec {
1487 label: self.label.to_string(),
1488 ty: self.ty.into_portable(registry),
1489 }
1490 }
1491}
1492
1493impl<F> MessageParamSpec<F>
1494where
1495 F: Form,
1496 TypeSpec<F>: Default,
1497{
1498 pub fn new(label: F::String) -> MessageParamSpecBuilder<F> {
1500 MessageParamSpecBuilder {
1501 spec: Self {
1502 label,
1503 ty: TypeSpec::default(),
1505 },
1506 }
1507 }
1508
1509 pub fn label(&self) -> &F::String {
1511 &self.label
1512 }
1513
1514 pub fn ty(&self) -> &TypeSpec<F> {
1516 &self.ty
1517 }
1518}
1519
1520#[must_use]
1522pub struct MessageParamSpecBuilder<F: Form> {
1523 spec: MessageParamSpec<F>,
1525}
1526
1527impl<F> MessageParamSpecBuilder<F>
1528where
1529 F: Form,
1530{
1531 pub fn of_type(self, ty: TypeSpec<F>) -> Self {
1533 let mut this = self;
1534 this.spec.ty = ty;
1535 this
1536 }
1537
1538 pub fn done(self) -> MessageParamSpec<F> {
1540 self.spec
1541 }
1542}
1543
1544#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1546#[serde(bound(
1547 serialize = "F::Type: Serialize, F::String: Serialize",
1548 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1549))]
1550#[serde(rename_all = "camelCase")]
1551pub struct EnvironmentSpec<F: Form = MetaForm>
1552where
1553 TypeSpec<F>: Default,
1554{
1555 account_id: TypeSpec<F>,
1556 balance: TypeSpec<F>,
1557 hash: TypeSpec<F>,
1558 timestamp: TypeSpec<F>,
1559 block_number: TypeSpec<F>,
1560 chain_extension: TypeSpec<F>,
1561 max_event_topics: usize,
1562 static_buffer_size: usize,
1563}
1564
1565impl<F> Default for EnvironmentSpec<F>
1566where
1567 F: Form,
1568 TypeSpec<F>: Default,
1569{
1570 fn default() -> Self {
1571 Self {
1572 account_id: Default::default(),
1573 balance: Default::default(),
1574 hash: Default::default(),
1575 timestamp: Default::default(),
1576 block_number: Default::default(),
1577 chain_extension: Default::default(),
1578 max_event_topics: Default::default(),
1579 static_buffer_size: Default::default(),
1580 }
1581 }
1582}
1583
1584impl IntoPortable for EnvironmentSpec {
1585 type Output = EnvironmentSpec<PortableForm>;
1586
1587 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1588 EnvironmentSpec {
1589 account_id: self.account_id.into_portable(registry),
1590 balance: self.balance.into_portable(registry),
1591 hash: self.hash.into_portable(registry),
1592 timestamp: self.timestamp.into_portable(registry),
1593 block_number: self.block_number.into_portable(registry),
1594 chain_extension: self.chain_extension.into_portable(registry),
1595 max_event_topics: self.max_event_topics,
1596 static_buffer_size: self.static_buffer_size,
1597 }
1598 }
1599}
1600
1601impl<F> EnvironmentSpec<F>
1602where
1603 F: Form,
1604 TypeSpec<F>: Default,
1605{
1606 pub fn account_id(&self) -> &TypeSpec<F> {
1608 &self.account_id
1609 }
1610 pub fn balance(&self) -> &TypeSpec<F> {
1612 &self.balance
1613 }
1614 pub fn hash(&self) -> &TypeSpec<F> {
1616 &self.hash
1617 }
1618 pub fn timestamp(&self) -> &TypeSpec<F> {
1620 &self.timestamp
1621 }
1622 pub fn block_number(&self) -> &TypeSpec<F> {
1624 &self.block_number
1625 }
1626 pub fn chain_extension(&self) -> &TypeSpec<F> {
1628 &self.chain_extension
1629 }
1630 pub fn max_event_topics(&self) -> usize {
1632 self.max_event_topics
1633 }
1634}
1635
1636#[allow(clippy::type_complexity)]
1637impl<F> EnvironmentSpec<F>
1638where
1639 F: Form,
1640 TypeSpec<F>: Default,
1641 EnvironmentSpec<F>: Default,
1642{
1643 pub fn new() -> EnvironmentSpecBuilder<
1644 F,
1645 Missing<state::AccountId>,
1646 Missing<state::Balance>,
1647 Missing<state::Hash>,
1648 Missing<state::Timestamp>,
1649 Missing<state::BlockNumber>,
1650 Missing<state::ChainExtension>,
1651 Missing<state::MaxEventTopics>,
1652 Missing<state::BufferSize>,
1653 > {
1654 EnvironmentSpecBuilder {
1655 spec: Default::default(),
1656 marker: PhantomData,
1657 }
1658 }
1659}
1660
1661#[allow(clippy::type_complexity)]
1663#[must_use]
1664pub struct EnvironmentSpecBuilder<F, A, B, H, T, BN, C, M, BS>
1665where
1666 F: Form,
1667 TypeSpec<F>: Default,
1668 EnvironmentSpec<F>: Default,
1669{
1670 spec: EnvironmentSpec<F>,
1671 marker: PhantomData<fn() -> (A, B, H, T, BN, C, M, BS)>,
1672}
1673
1674impl<F, B, H, T, BN, C, M, BS>
1675 EnvironmentSpecBuilder<F, Missing<state::AccountId>, B, H, T, BN, C, M, BS>
1676where
1677 F: Form,
1678 TypeSpec<F>: Default,
1679 EnvironmentSpec<F>: Default,
1680{
1681 pub fn account_id(
1683 self,
1684 account_id: TypeSpec<F>,
1685 ) -> EnvironmentSpecBuilder<F, state::AccountId, B, H, T, BN, C, M, BS> {
1686 EnvironmentSpecBuilder {
1687 spec: EnvironmentSpec {
1688 account_id,
1689 ..self.spec
1690 },
1691 marker: PhantomData,
1692 }
1693 }
1694}
1695
1696impl<F, A, H, T, BN, C, M, BS>
1697 EnvironmentSpecBuilder<F, A, Missing<state::Balance>, H, T, BN, C, M, BS>
1698where
1699 F: Form,
1700 TypeSpec<F>: Default,
1701 EnvironmentSpec<F>: Default,
1702{
1703 pub fn balance(
1705 self,
1706 balance: TypeSpec<F>,
1707 ) -> EnvironmentSpecBuilder<F, A, state::Balance, H, T, BN, C, M, BS> {
1708 EnvironmentSpecBuilder {
1709 spec: EnvironmentSpec {
1710 balance,
1711 ..self.spec
1712 },
1713 marker: PhantomData,
1714 }
1715 }
1716}
1717
1718impl<F, A, B, T, BN, C, M, BS>
1719 EnvironmentSpecBuilder<F, A, B, Missing<state::Hash>, T, BN, C, M, BS>
1720where
1721 F: Form,
1722 TypeSpec<F>: Default,
1723 EnvironmentSpec<F>: Default,
1724{
1725 pub fn hash(
1727 self,
1728 hash: TypeSpec<F>,
1729 ) -> EnvironmentSpecBuilder<F, A, B, state::Hash, T, BN, C, M, BS> {
1730 EnvironmentSpecBuilder {
1731 spec: EnvironmentSpec { hash, ..self.spec },
1732 marker: PhantomData,
1733 }
1734 }
1735}
1736
1737impl<F, A, B, H, BN, C, M, BS>
1738 EnvironmentSpecBuilder<F, A, B, H, Missing<state::Timestamp>, BN, C, M, BS>
1739where
1740 F: Form,
1741 TypeSpec<F>: Default,
1742 EnvironmentSpec<F>: Default,
1743{
1744 pub fn timestamp(
1746 self,
1747 timestamp: TypeSpec<F>,
1748 ) -> EnvironmentSpecBuilder<F, A, B, H, state::Timestamp, BN, C, M, BS> {
1749 EnvironmentSpecBuilder {
1750 spec: EnvironmentSpec {
1751 timestamp,
1752 ..self.spec
1753 },
1754 marker: PhantomData,
1755 }
1756 }
1757}
1758
1759impl<F, A, B, H, T, C, M, BS>
1760 EnvironmentSpecBuilder<F, A, B, H, T, Missing<state::BlockNumber>, C, M, BS>
1761where
1762 F: Form,
1763 TypeSpec<F>: Default,
1764 EnvironmentSpec<F>: Default,
1765{
1766 pub fn block_number(
1768 self,
1769 block_number: TypeSpec<F>,
1770 ) -> EnvironmentSpecBuilder<F, A, B, H, T, state::BlockNumber, C, M, BS> {
1771 EnvironmentSpecBuilder {
1772 spec: EnvironmentSpec {
1773 block_number,
1774 ..self.spec
1775 },
1776 marker: PhantomData,
1777 }
1778 }
1779}
1780
1781impl<F, A, B, H, T, BN, M, BS>
1782 EnvironmentSpecBuilder<F, A, B, H, T, BN, Missing<state::ChainExtension>, M, BS>
1783where
1784 F: Form,
1785 TypeSpec<F>: Default,
1786 EnvironmentSpec<F>: Default,
1787{
1788 pub fn chain_extension(
1790 self,
1791 chain_extension: TypeSpec<F>,
1792 ) -> EnvironmentSpecBuilder<F, A, B, H, T, BN, state::ChainExtension, M, BS> {
1793 EnvironmentSpecBuilder {
1794 spec: EnvironmentSpec {
1795 chain_extension,
1796 ..self.spec
1797 },
1798 marker: PhantomData,
1799 }
1800 }
1801}
1802
1803impl<F, A, B, H, T, BN, C, BS>
1804 EnvironmentSpecBuilder<F, A, B, H, T, BN, C, Missing<state::MaxEventTopics>, BS>
1805where
1806 F: Form,
1807 TypeSpec<F>: Default,
1808 EnvironmentSpec<F>: Default,
1809{
1810 pub fn max_event_topics(
1812 self,
1813 max_event_topics: usize,
1814 ) -> EnvironmentSpecBuilder<F, A, B, H, T, BN, C, state::MaxEventTopics, BS> {
1815 EnvironmentSpecBuilder {
1816 spec: EnvironmentSpec {
1817 max_event_topics,
1818 ..self.spec
1819 },
1820 marker: PhantomData,
1821 }
1822 }
1823}
1824
1825impl<F, A, B, H, T, BN, C, M>
1826 EnvironmentSpecBuilder<F, A, B, H, T, BN, C, M, Missing<state::BufferSize>>
1827where
1828 F: Form,
1829 TypeSpec<F>: Default,
1830 EnvironmentSpec<F>: Default,
1831{
1832 pub fn static_buffer_size(
1834 self,
1835 static_buffer_size: usize,
1836 ) -> EnvironmentSpecBuilder<F, A, B, H, T, BN, C, M, state::BufferSize> {
1837 EnvironmentSpecBuilder {
1838 spec: EnvironmentSpec {
1839 static_buffer_size,
1840 ..self.spec
1841 },
1842 marker: PhantomData,
1843 }
1844 }
1845}
1846
1847impl<F>
1848 EnvironmentSpecBuilder<
1849 F,
1850 state::AccountId,
1851 state::Balance,
1852 state::Hash,
1853 state::Timestamp,
1854 state::BlockNumber,
1855 state::ChainExtension,
1856 state::MaxEventTopics,
1857 state::BufferSize,
1858 >
1859where
1860 F: Form,
1861 TypeSpec<F>: Default,
1862 EnvironmentSpec<F>: Default,
1863{
1864 pub fn done(self) -> EnvironmentSpec<F> {
1866 self.spec
1867 }
1868}