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 IntoPortable,
39 Registry,
40 TypeInfo,
41 form::{
42 Form,
43 MetaForm,
44 PortableForm,
45 },
46 meta_type,
47};
48use schemars::JsonSchema;
49use serde::{
50 Deserialize,
51 Serialize,
52 de::DeserializeOwned,
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<F> ContractSpecBuilder<F, Valid>
258where
259 F: Form,
260 F::String: Display,
261 TypeSpec<F>: Default,
262{
263 #[allow(clippy::arithmetic_side_effects)] pub fn done(self) -> ContractSpec<F> {
266 assert!(
267 !self.spec.constructors.is_empty(),
268 "must have at least one constructor"
269 );
270 assert!(
271 !self.spec.messages.is_empty(),
272 "must have at least one message"
273 );
274 assert!(
275 self.spec.constructors.iter().filter(|c| c.default).count() < 2,
276 "only one default constructor is allowed"
277 );
278 assert!(
279 self.spec.messages.iter().filter(|m| m.default).count() < 2,
280 "only one default message is allowed"
281 );
282
283 const MAX_TOPICS: usize = 4;
284 let events_exceeding_max_topics_limit = self
285 .spec
286 .events
287 .iter()
288 .filter_map(|e| {
289 let signature_topic = if e.signature_topic.is_some() { 1 } else { 0 };
290 let topics_count =
291 signature_topic + e.args.iter().filter(|a| a.indexed).count();
292 if topics_count > MAX_TOPICS {
293 Some(format!(
294 "`{}::{}` ({} topics)",
295 e.module_path, e.label, topics_count
296 ))
297 } else {
298 None
299 }
300 })
301 .collect::<Vec<_>>();
302 assert!(
303 events_exceeding_max_topics_limit.is_empty(),
304 "maximum of {MAX_TOPICS} event topics exceeded: {}",
305 events_exceeding_max_topics_limit.join(", ")
306 );
307
308 let mut signature_topics: BTreeMap<Vec<u8>, Vec<String>> = BTreeMap::new();
309 for e in self.spec.events.iter() {
310 if let Some(signature_topic) = &e.signature_topic {
311 signature_topics
312 .entry(signature_topic.bytes.clone())
313 .or_default()
314 .push(format!("`{}::{}`", e.module_path, e.label));
315 }
316 }
317 let signature_topic_collisions = signature_topics
318 .iter()
319 .filter_map(|(_, topics)| {
320 if topics.len() > 1 {
321 Some(format!(
322 "event signature topic collision: {}",
323 topics.join(", ")
324 ))
325 } else {
326 None
327 }
328 })
329 .collect::<Vec<_>>();
330 assert!(
331 signature_topic_collisions.is_empty(),
332 "{}",
333 signature_topic_collisions.join("\n")
334 );
335
336 self.spec
337 }
338}
339
340impl<F> ContractSpec<F>
341where
342 F: Form,
343 TypeSpec<F>: Default,
344 EnvironmentSpec<F>: Default,
345{
346 pub fn new() -> ContractSpecBuilder<F, Invalid> {
348 ContractSpecBuilder {
349 spec: Self {
350 constructors: Vec::new(),
351 messages: Vec::new(),
352 events: Vec::new(),
353 docs: Vec::new(),
354 lang_error: Default::default(),
355 environment: Default::default(),
356 },
357 marker: PhantomData,
358 }
359 }
360}
361
362#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
364#[serde(bound(
365 serialize = "F::Type: Serialize, F::String: Serialize",
366 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned",
367))]
368#[serde(rename_all = "camelCase")]
369pub struct ConstructorSpec<F: Form = MetaForm> {
370 pub label: F::String,
375 pub selector: Selector,
377 pub payable: bool,
379 pub args: Vec<MessageParamSpec<F>>,
381 pub return_type: ReturnTypeSpec<F>,
383 pub docs: Vec<F::String>,
385 default: bool,
387}
388
389impl IntoPortable for ConstructorSpec {
390 type Output = ConstructorSpec<PortableForm>;
391
392 fn into_portable(self, registry: &mut Registry) -> Self::Output {
393 ConstructorSpec {
394 label: self.label.to_string(),
395 selector: self.selector,
396 payable: self.payable,
397 args: self
398 .args
399 .into_iter()
400 .map(|arg| arg.into_portable(registry))
401 .collect::<Vec<_>>(),
402 return_type: self.return_type.into_portable(registry),
403 docs: self.docs.into_iter().map(|s| s.into()).collect(),
404 default: self.default,
405 }
406 }
407}
408
409impl<F> ConstructorSpec<F>
410where
411 F: Form,
412{
413 pub fn label(&self) -> &F::String {
418 &self.label
419 }
420
421 pub fn selector(&self) -> &Selector {
423 &self.selector
424 }
425
426 pub fn payable(&self) -> bool {
428 self.payable
429 }
430
431 pub fn args(&self) -> &[MessageParamSpec<F>] {
433 &self.args
434 }
435
436 pub fn return_type(&self) -> &ReturnTypeSpec<F> {
438 &self.return_type
439 }
440
441 pub fn docs(&self) -> &[F::String] {
443 &self.docs
444 }
445
446 pub fn default(&self) -> bool {
447 self.default
448 }
449}
450
451#[allow(clippy::type_complexity)]
459#[must_use]
460pub struct ConstructorSpecBuilder<F: Form, Selector, IsPayable, Returns> {
461 spec: ConstructorSpec<F>,
462 marker: PhantomData<fn() -> (Selector, IsPayable, Returns)>,
463}
464
465impl<F> ConstructorSpec<F>
466where
467 F: Form,
468 TypeSpec<F>: Default,
469{
470 pub fn from_label(
472 label: <F as Form>::String,
473 ) -> ConstructorSpecBuilder<
474 F,
475 Missing<state::Selector>,
476 Missing<state::IsPayable>,
477 Missing<state::Returns>,
478 > {
479 ConstructorSpecBuilder {
480 spec: Self {
481 label,
482 selector: Selector::default(),
483 payable: Default::default(),
484 args: Vec::new(),
485 return_type: ReturnTypeSpec::new(TypeSpec::default()),
486 docs: Vec::new(),
487 default: false,
488 },
489 marker: PhantomData,
490 }
491 }
492}
493
494impl<F, P, R> ConstructorSpecBuilder<F, Missing<state::Selector>, P, R>
495where
496 F: Form,
497{
498 pub fn selector(
500 self,
501 selector: [u8; 4],
502 ) -> ConstructorSpecBuilder<F, state::Selector, P, R> {
503 ConstructorSpecBuilder {
504 spec: ConstructorSpec {
505 selector: selector.into(),
506 ..self.spec
507 },
508 marker: PhantomData,
509 }
510 }
511}
512
513impl<F, S, R> ConstructorSpecBuilder<F, S, Missing<state::IsPayable>, R>
514where
515 F: Form,
516{
517 pub fn payable(
519 self,
520 is_payable: bool,
521 ) -> ConstructorSpecBuilder<F, S, state::IsPayable, R> {
522 ConstructorSpecBuilder {
523 spec: ConstructorSpec {
524 payable: is_payable,
525 ..self.spec
526 },
527 marker: PhantomData,
528 }
529 }
530}
531
532impl<F, S, P> ConstructorSpecBuilder<F, S, P, Missing<state::Returns>>
533where
534 F: Form,
535{
536 pub fn returns(
538 self,
539 return_type: ReturnTypeSpec<F>,
540 ) -> ConstructorSpecBuilder<F, S, P, state::Returns> {
541 ConstructorSpecBuilder {
542 spec: ConstructorSpec {
543 return_type,
544 ..self.spec
545 },
546 marker: PhantomData,
547 }
548 }
549}
550
551impl<F, S, P, R> ConstructorSpecBuilder<F, S, P, R>
552where
553 F: Form,
554{
555 pub fn args<A>(self, args: A) -> Self
557 where
558 A: IntoIterator<Item = MessageParamSpec<F>>,
559 {
560 let mut this = self;
561 debug_assert!(this.spec.args.is_empty());
562 this.spec.args = args.into_iter().collect::<Vec<_>>();
563 this
564 }
565
566 pub fn docs<'a, D>(self, docs: D) -> Self
568 where
569 D: IntoIterator<Item = &'a str>,
570 F::String: From<&'a str>,
571 {
572 let mut this = self;
573 debug_assert!(this.spec.docs.is_empty());
574 this.spec.docs = docs
575 .into_iter()
576 .map(|s| trim_extra_whitespace(s).into())
577 .collect::<Vec<_>>();
578 this
579 }
580
581 pub fn default(self, default: bool) -> Self {
583 ConstructorSpecBuilder {
584 spec: ConstructorSpec {
585 default,
586 ..self.spec
587 },
588 marker: PhantomData,
589 }
590 }
591}
592
593impl<F> ConstructorSpecBuilder<F, state::Selector, state::IsPayable, state::Returns>
594where
595 F: Form,
596{
597 pub fn done(self) -> ConstructorSpec<F> {
599 self.spec
600 }
601}
602
603#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
605#[serde(bound(
606 serialize = "F::Type: Serialize, F::String: Serialize",
607 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
608))]
609#[serde(rename_all = "camelCase")]
610pub struct MessageSpec<F: Form = MetaForm> {
611 label: F::String,
616 selector: Selector,
618 mutates: bool,
620 payable: bool,
622 args: Vec<MessageParamSpec<F>>,
624 return_type: ReturnTypeSpec<F>,
626 docs: Vec<F::String>,
628 default: bool,
630}
631
632pub struct Missing<S>(PhantomData<fn() -> S>);
635
636mod state {
637 pub struct Selector;
642 pub struct Mutates;
644 pub struct IsPayable;
646 pub struct Returns;
648 pub struct AccountId;
650 pub struct Balance;
652 pub struct Hash;
654 pub struct Timestamp;
656 pub struct BlockNumber;
658 pub struct NativeToEthRatio;
660 pub struct TrustBackedAssetsPrecompileIndex;
663 pub struct PoolAssetsPrecompileIndex;
665 pub struct BufferSize;
667}
668
669impl<F> MessageSpec<F>
670where
671 F: Form,
672 TypeSpec<F>: Default,
673{
674 pub fn from_label(
676 label: <F as Form>::String,
677 ) -> MessageSpecBuilder<
678 F,
679 Missing<state::Selector>,
680 Missing<state::Mutates>,
681 Missing<state::IsPayable>,
682 Missing<state::Returns>,
683 > {
684 MessageSpecBuilder {
685 spec: Self {
686 label,
687 selector: Selector::default(),
688 mutates: false,
689 payable: false,
690 args: Vec::new(),
691 return_type: ReturnTypeSpec::new(TypeSpec::default()),
692 docs: Vec::new(),
693 default: false,
694 },
695 marker: PhantomData,
696 }
697 }
698}
699
700impl<F> MessageSpec<F>
701where
702 F: Form,
703{
704 pub fn label(&self) -> &F::String {
709 &self.label
710 }
711
712 pub fn selector(&self) -> &Selector {
714 &self.selector
715 }
716
717 pub fn mutates(&self) -> bool {
719 self.mutates
720 }
721
722 pub fn payable(&self) -> bool {
724 self.payable
725 }
726
727 pub fn args(&self) -> &[MessageParamSpec<F>] {
729 &self.args
730 }
731
732 pub fn return_type(&self) -> &ReturnTypeSpec<F> {
734 &self.return_type
735 }
736
737 pub fn docs(&self) -> &[F::String] {
739 &self.docs
740 }
741
742 pub fn default(&self) -> bool {
743 self.default
744 }
745}
746
747#[allow(clippy::type_complexity)]
755#[must_use]
756pub struct MessageSpecBuilder<F, Selector, Mutates, IsPayable, Returns>
757where
758 F: Form,
759{
760 spec: MessageSpec<F>,
761 marker: PhantomData<fn() -> (Selector, Mutates, IsPayable, Returns)>,
762}
763
764impl<F, M, P, R> MessageSpecBuilder<F, Missing<state::Selector>, M, P, R>
765where
766 F: Form,
767{
768 pub fn selector(
770 self,
771 selector: [u8; 4],
772 ) -> MessageSpecBuilder<F, state::Selector, M, P, R> {
773 MessageSpecBuilder {
774 spec: MessageSpec {
775 selector: selector.into(),
776 ..self.spec
777 },
778 marker: PhantomData,
779 }
780 }
781}
782
783impl<F, S, P, R> MessageSpecBuilder<F, S, Missing<state::Mutates>, P, R>
784where
785 F: Form,
786{
787 pub fn mutates(
790 self,
791 mutates: bool,
792 ) -> MessageSpecBuilder<F, S, state::Mutates, P, R> {
793 MessageSpecBuilder {
794 spec: MessageSpec {
795 mutates,
796 ..self.spec
797 },
798 marker: PhantomData,
799 }
800 }
801}
802
803impl<F, S, M, R> MessageSpecBuilder<F, S, M, Missing<state::IsPayable>, R>
804where
805 F: Form,
806{
807 pub fn payable(
809 self,
810 is_payable: bool,
811 ) -> MessageSpecBuilder<F, S, M, state::IsPayable, R> {
812 MessageSpecBuilder {
813 spec: MessageSpec {
814 payable: is_payable,
815 ..self.spec
816 },
817 marker: PhantomData,
818 }
819 }
820}
821
822impl<F, M, S, P> MessageSpecBuilder<F, S, M, P, Missing<state::Returns>>
823where
824 F: Form,
825{
826 pub fn returns(
828 self,
829 return_type: ReturnTypeSpec<F>,
830 ) -> MessageSpecBuilder<F, S, M, P, state::Returns> {
831 MessageSpecBuilder {
832 spec: MessageSpec {
833 return_type,
834 ..self.spec
835 },
836 marker: PhantomData,
837 }
838 }
839}
840
841impl<F, S, M, P, R> MessageSpecBuilder<F, S, M, P, R>
842where
843 F: Form,
844{
845 pub fn args<A>(self, args: A) -> Self
847 where
848 A: IntoIterator<Item = MessageParamSpec<F>>,
849 {
850 let mut this = self;
851 debug_assert!(this.spec.args.is_empty());
852 this.spec.args = args.into_iter().collect::<Vec<_>>();
853 this
854 }
855
856 pub fn docs<D>(self, docs: D) -> Self
858 where
859 D: IntoIterator<Item = <F as Form>::String>,
860 {
861 let mut this = self;
862 debug_assert!(this.spec.docs.is_empty());
863 this.spec.docs = docs.into_iter().collect::<Vec<_>>();
864 this
865 }
866
867 pub fn default(self, default: bool) -> Self {
869 MessageSpecBuilder {
870 spec: MessageSpec {
871 default,
872 ..self.spec
873 },
874 marker: PhantomData,
875 }
876 }
877}
878
879impl<F>
880 MessageSpecBuilder<
881 F,
882 state::Selector,
883 state::Mutates,
884 state::IsPayable,
885 state::Returns,
886 >
887where
888 F: Form,
889{
890 pub fn done(self) -> MessageSpec<F> {
892 self.spec
893 }
894}
895
896impl IntoPortable for MessageSpec {
897 type Output = MessageSpec<PortableForm>;
898
899 fn into_portable(self, registry: &mut Registry) -> Self::Output {
900 MessageSpec {
901 label: self.label.to_string(),
902 selector: self.selector,
903 mutates: self.mutates,
904 payable: self.payable,
905 default: self.default,
906 args: self
907 .args
908 .into_iter()
909 .map(|arg| arg.into_portable(registry))
910 .collect::<Vec<_>>(),
911 return_type: self.return_type.into_portable(registry),
912 docs: self.docs.into_iter().map(|s| s.into()).collect(),
913 }
914 }
915}
916
917#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
919#[serde(bound(
920 serialize = "F::Type: Serialize, F::String: Serialize",
921 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
922))]
923pub struct EventSpec<F: Form = MetaForm> {
924 label: F::String,
926 module_path: F::String,
928 signature_topic: Option<SignatureTopic>,
930 args: Vec<EventParamSpec<F>>,
932 docs: Vec<F::String>,
934}
935
936#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
938#[serde(transparent)]
939pub struct SignatureTopic {
940 #[serde(
941 serialize_with = "serialize_as_byte_str",
942 deserialize_with = "deserialize_from_byte_str"
943 )]
944 bytes: Vec<u8>,
945}
946
947impl<T> From<T> for SignatureTopic
948where
949 T: AsRef<[u8]>,
950{
951 fn from(bytes: T) -> Self {
952 SignatureTopic {
953 bytes: bytes.as_ref().to_vec(),
954 }
955 }
956}
957
958impl SignatureTopic {
959 pub fn as_bytes(&self) -> &[u8] {
961 &self.bytes
962 }
963}
964
965#[must_use]
967pub struct EventSpecBuilder<F>
968where
969 F: Form,
970{
971 spec: EventSpec<F>,
972}
973
974impl<F> EventSpecBuilder<F>
975where
976 F: Form,
977{
978 pub fn module_path<'a>(self, path: &'a str) -> Self
980 where
981 F::String: From<&'a str>,
982 {
983 let mut this = self;
984 this.spec.module_path = path.into();
985 this
986 }
987
988 pub fn args<A>(self, args: A) -> Self
990 where
991 A: IntoIterator<Item = EventParamSpec<F>>,
992 {
993 let mut this = self;
994 debug_assert!(this.spec.args.is_empty());
995 this.spec.args = args.into_iter().collect::<Vec<_>>();
996 this
997 }
998
999 pub fn signature_topic<T>(self, topic: Option<T>) -> Self
1001 where
1002 T: AsRef<[u8]>,
1003 {
1004 let mut this = self;
1005 debug_assert!(this.spec.signature_topic.is_none());
1006 this.spec.signature_topic = topic.as_ref().map(SignatureTopic::from);
1007 this
1008 }
1009
1010 pub fn docs<'a, D>(self, docs: D) -> Self
1012 where
1013 D: IntoIterator<Item = &'a str>,
1014 F::String: From<&'a str>,
1015 {
1016 let mut this = self;
1017 debug_assert!(this.spec.docs.is_empty());
1018 this.spec.docs = docs
1019 .into_iter()
1020 .map(|s| trim_extra_whitespace(s).into())
1021 .collect::<Vec<_>>();
1022 this
1023 }
1024
1025 pub fn done(self) -> EventSpec<F> {
1027 self.spec
1028 }
1029}
1030
1031impl IntoPortable for EventSpec {
1032 type Output = EventSpec<PortableForm>;
1033
1034 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1035 EventSpec {
1036 label: self.label.to_string(),
1037 module_path: self.module_path.to_string(),
1038 signature_topic: self.signature_topic,
1039 args: self
1040 .args
1041 .into_iter()
1042 .map(|arg| arg.into_portable(registry))
1043 .collect::<Vec<_>>(),
1044 docs: self.docs.into_iter().map(|s| s.into()).collect(),
1045 }
1046 }
1047}
1048
1049impl<F> EventSpec<F>
1050where
1051 F: Form,
1052 F::String: Default,
1053{
1054 pub fn new(label: <F as Form>::String) -> EventSpecBuilder<F> {
1056 EventSpecBuilder {
1057 spec: Self {
1058 label,
1059 module_path: Default::default(),
1060 signature_topic: None,
1061 args: Vec::new(),
1062 docs: Vec::new(),
1063 },
1064 }
1065 }
1066}
1067
1068impl<F> EventSpec<F>
1069where
1070 F: Form,
1071{
1072 pub fn label(&self) -> &F::String {
1074 &self.label
1075 }
1076
1077 pub fn args(&self) -> &[EventParamSpec<F>] {
1079 &self.args
1080 }
1081
1082 pub fn signature_topic(&self) -> Option<&SignatureTopic> {
1084 self.signature_topic.as_ref()
1085 }
1086
1087 pub fn docs(&self) -> &[F::String] {
1089 &self.docs
1090 }
1091}
1092
1093#[cfg_attr(feature = "std", derive(Hash))]
1095#[derive(Debug, Default, PartialEq, Eq, derive_more::From, JsonSchema)]
1096pub struct Selector(#[schemars(with = "String")] [u8; 4]);
1097
1098impl serde::Serialize for Selector {
1099 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1100 where
1101 S: serde::Serializer,
1102 {
1103 serde_hex::serialize(&self.0, serializer)
1104 }
1105}
1106
1107impl<'de> serde::Deserialize<'de> for Selector {
1108 fn deserialize<D>(d: D) -> Result<Self, D::Error>
1109 where
1110 D: serde::Deserializer<'de>,
1111 {
1112 let mut arr = [0; 4];
1113 serde_hex::deserialize_check_len(d, serde_hex::ExpectedLen::Exact(&mut arr[..]))?;
1114 Ok(arr.into())
1115 }
1116}
1117
1118impl Selector {
1119 pub fn new<T>(bytes: T) -> Self
1121 where
1122 T: Into<[u8; 4]>,
1123 {
1124 Self(bytes.into())
1125 }
1126
1127 pub fn to_bytes(&self) -> &[u8] {
1129 &self.0
1130 }
1131}
1132
1133pub type DisplayName<F> = scale_info::Path<F>;
1151
1152#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1170#[serde(bound(
1171 serialize = "F::Type: Serialize, F::String: Serialize",
1172 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1173))]
1174#[serde(rename_all = "camelCase")]
1175pub struct TypeSpec<F: Form = MetaForm> {
1176 #[serde(rename = "type")]
1178 ty: F::Type,
1179 display_name: DisplayName<F>,
1181}
1182
1183impl Default for TypeSpec<MetaForm> {
1184 fn default() -> Self {
1185 TypeSpec::of_type::<()>()
1186 }
1187}
1188
1189impl Default for TypeSpec<PortableForm> {
1190 fn default() -> Self {
1191 Self {
1192 ty: u32::default().into(),
1193 display_name: Default::default(),
1194 }
1195 }
1196}
1197
1198impl IntoPortable for TypeSpec {
1199 type Output = TypeSpec<PortableForm>;
1200
1201 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1202 TypeSpec {
1203 ty: registry.register_type(&self.ty),
1204 display_name: self.display_name.into_portable(registry),
1205 }
1206 }
1207}
1208
1209impl TypeSpec {
1210 pub fn with_name_str<T>(display_name: &'static str) -> Self
1222 where
1223 T: TypeInfo + 'static,
1224 {
1225 Self::with_name_segs::<T, _>(display_name.split("::"))
1226 }
1227
1228 pub fn with_name_segs<T, S>(segments: S) -> Self
1241 where
1242 T: TypeInfo + 'static,
1243 S: IntoIterator<Item = &'static str>,
1244 {
1245 Self {
1246 ty: meta_type::<T>(),
1247 display_name: DisplayName::from_segments(segments)
1248 .unwrap_or_else(|err| panic!("display name is invalid: {err:?}")),
1249 }
1250 }
1251
1252 pub fn of_type<T>() -> Self
1260 where
1261 T: TypeInfo + 'static,
1262 {
1263 Self {
1264 ty: meta_type::<T>(),
1265 display_name: DisplayName::default(),
1266 }
1267 }
1268}
1269
1270impl<F> TypeSpec<F>
1271where
1272 F: Form,
1273{
1274 pub fn ty(&self) -> &F::Type {
1276 &self.ty
1277 }
1278
1279 pub fn display_name(&self) -> &DisplayName<F> {
1281 &self.display_name
1282 }
1283
1284 pub fn new(ty: <F as Form>::Type, display_name: DisplayName<F>) -> Self {
1286 Self { ty, display_name }
1287 }
1288}
1289
1290#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1292#[serde(bound(
1293 serialize = "F::Type: Serialize, F::String: Serialize",
1294 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1295))]
1296pub struct EventParamSpec<F: Form = MetaForm> {
1297 label: F::String,
1299 indexed: bool,
1301 #[serde(rename = "type")]
1303 ty: TypeSpec<F>,
1304 docs: Vec<F::String>,
1306}
1307
1308impl IntoPortable for EventParamSpec {
1309 type Output = EventParamSpec<PortableForm>;
1310
1311 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1312 EventParamSpec {
1313 label: self.label.to_string(),
1314 indexed: self.indexed,
1315 ty: self.ty.into_portable(registry),
1316 docs: self.docs.into_iter().map(|s| s.into()).collect(),
1317 }
1318 }
1319}
1320
1321impl<F> EventParamSpec<F>
1322where
1323 F: Form,
1324 TypeSpec<F>: Default,
1325{
1326 pub fn new(label: F::String) -> EventParamSpecBuilder<F> {
1328 EventParamSpecBuilder {
1329 spec: Self {
1330 label,
1331 indexed: false,
1333 ty: Default::default(),
1335 docs: vec![],
1337 },
1338 }
1339 }
1340 pub fn label(&self) -> &F::String {
1342 &self.label
1343 }
1344
1345 pub fn indexed(&self) -> bool {
1347 self.indexed
1348 }
1349
1350 pub fn ty(&self) -> &TypeSpec<F> {
1352 &self.ty
1353 }
1354
1355 pub fn docs(&self) -> &[F::String] {
1357 &self.docs
1358 }
1359}
1360
1361#[must_use]
1363pub struct EventParamSpecBuilder<F>
1364where
1365 F: Form,
1366{
1367 spec: EventParamSpec<F>,
1369}
1370
1371impl<F> EventParamSpecBuilder<F>
1372where
1373 F: Form,
1374{
1375 pub fn of_type(self, spec: TypeSpec<F>) -> Self {
1377 let mut this = self;
1378 this.spec.ty = spec;
1379 this
1380 }
1381
1382 pub fn indexed(self, is_indexed: bool) -> Self {
1384 let mut this = self;
1385 this.spec.indexed = is_indexed;
1386 this
1387 }
1388
1389 pub fn docs<'a, D>(self, docs: D) -> Self
1391 where
1392 D: IntoIterator<Item = &'a str>,
1393 F::String: From<&'a str>,
1394 {
1395 debug_assert!(self.spec.docs.is_empty());
1396 Self {
1397 spec: EventParamSpec {
1398 docs: docs
1399 .into_iter()
1400 .map(|s| trim_extra_whitespace(s).into())
1401 .collect::<Vec<_>>(),
1402 ..self.spec
1403 },
1404 }
1405 }
1406
1407 pub fn done(self) -> EventParamSpec<F> {
1409 self.spec
1410 }
1411}
1412
1413#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1415#[serde(transparent)]
1416#[serde(bound(
1417 serialize = "F::Type: Serialize, F::String: Serialize",
1418 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1419))]
1420#[must_use]
1421pub struct ReturnTypeSpec<F: Form = MetaForm> {
1422 #[serde(rename = "type")]
1423 ret_type: TypeSpec<F>,
1424}
1425
1426impl IntoPortable for ReturnTypeSpec {
1427 type Output = ReturnTypeSpec<PortableForm>;
1428
1429 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1430 ReturnTypeSpec {
1431 ret_type: self.ret_type.into_portable(registry),
1432 }
1433 }
1434}
1435
1436impl<F> ReturnTypeSpec<F>
1437where
1438 F: Form,
1439 TypeSpec<F>: Default,
1440{
1441 pub fn new<T>(ty: T) -> Self
1450 where
1451 T: Into<TypeSpec<F>>,
1452 {
1453 Self {
1454 ret_type: ty.into(),
1455 }
1456 }
1457
1458 pub fn ret_type(&self) -> &TypeSpec<F> {
1460 &self.ret_type
1461 }
1462}
1463
1464#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1466#[serde(bound(
1467 serialize = "F::Type: Serialize, F::String: Serialize",
1468 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1469))]
1470pub struct MessageParamSpec<F: Form = MetaForm> {
1471 label: F::String,
1473 #[serde(rename = "type")]
1475 ty: TypeSpec<F>,
1476}
1477
1478impl IntoPortable for MessageParamSpec {
1479 type Output = MessageParamSpec<PortableForm>;
1480
1481 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1482 MessageParamSpec {
1483 label: self.label.to_string(),
1484 ty: self.ty.into_portable(registry),
1485 }
1486 }
1487}
1488
1489impl<F> MessageParamSpec<F>
1490where
1491 F: Form,
1492 TypeSpec<F>: Default,
1493{
1494 pub fn new(label: F::String) -> MessageParamSpecBuilder<F> {
1496 MessageParamSpecBuilder {
1497 spec: Self {
1498 label,
1499 ty: TypeSpec::default(),
1501 },
1502 }
1503 }
1504
1505 pub fn label(&self) -> &F::String {
1507 &self.label
1508 }
1509
1510 pub fn ty(&self) -> &TypeSpec<F> {
1512 &self.ty
1513 }
1514}
1515
1516#[must_use]
1518pub struct MessageParamSpecBuilder<F: Form> {
1519 spec: MessageParamSpec<F>,
1521}
1522
1523impl<F> MessageParamSpecBuilder<F>
1524where
1525 F: Form,
1526{
1527 pub fn of_type(self, ty: TypeSpec<F>) -> Self {
1529 let mut this = self;
1530 this.spec.ty = ty;
1531 this
1532 }
1533
1534 pub fn done(self) -> MessageParamSpec<F> {
1536 self.spec
1537 }
1538}
1539
1540#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1542#[serde(bound(
1543 serialize = "F::Type: Serialize, F::String: Serialize",
1544 deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1545))]
1546#[serde(rename_all = "camelCase")]
1547pub struct EnvironmentSpec<F: Form = MetaForm>
1548where
1549 TypeSpec<F>: Default,
1550{
1551 account_id: TypeSpec<F>,
1552 balance: TypeSpec<F>,
1553 hash: TypeSpec<F>,
1554 timestamp: TypeSpec<F>,
1555 block_number: TypeSpec<F>,
1556 native_to_eth_ratio: u32,
1557 trust_backed_assets_precompile_index: u16,
1558 pool_assets_precompile_index: u16,
1559 static_buffer_size: usize,
1560}
1561
1562impl<F> Default for EnvironmentSpec<F>
1563where
1564 F: Form,
1565 TypeSpec<F>: Default,
1566{
1567 fn default() -> Self {
1568 Self {
1569 account_id: Default::default(),
1570 balance: Default::default(),
1571 hash: Default::default(),
1572 timestamp: Default::default(),
1573 block_number: Default::default(),
1574 native_to_eth_ratio: Default::default(),
1575 trust_backed_assets_precompile_index: Default::default(),
1576 pool_assets_precompile_index: Default::default(),
1577 static_buffer_size: Default::default(),
1578 }
1579 }
1580}
1581
1582impl IntoPortable for EnvironmentSpec {
1583 type Output = EnvironmentSpec<PortableForm>;
1584
1585 fn into_portable(self, registry: &mut Registry) -> Self::Output {
1586 EnvironmentSpec {
1587 account_id: self.account_id.into_portable(registry),
1588 balance: self.balance.into_portable(registry),
1589 hash: self.hash.into_portable(registry),
1590 timestamp: self.timestamp.into_portable(registry),
1591 block_number: self.block_number.into_portable(registry),
1592 native_to_eth_ratio: self.native_to_eth_ratio,
1593 trust_backed_assets_precompile_index: self
1594 .trust_backed_assets_precompile_index,
1595 pool_assets_precompile_index: self.pool_assets_precompile_index,
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 native_to_eth_ratio(&self) -> u32 {
1628 self.native_to_eth_ratio
1629 }
1630 pub fn trust_backed_assets_precompile_index(&self) -> u16 {
1632 self.trust_backed_assets_precompile_index
1633 }
1634 pub fn pool_assets_precompile_index(&self) -> u16 {
1636 self.pool_assets_precompile_index
1637 }
1638}
1639
1640#[allow(clippy::type_complexity)]
1641impl<F> EnvironmentSpec<F>
1642where
1643 F: Form,
1644 TypeSpec<F>: Default,
1645 EnvironmentSpec<F>: Default,
1646{
1647 pub fn new() -> EnvironmentSpecBuilder<
1648 F,
1649 Missing<state::AccountId>,
1650 Missing<state::Balance>,
1651 Missing<state::Hash>,
1652 Missing<state::Timestamp>,
1653 Missing<state::BlockNumber>,
1654 Missing<state::NativeToEthRatio>,
1655 Missing<state::TrustBackedAssetsPrecompileIndex>,
1656 Missing<state::PoolAssetsPrecompileIndex>,
1657 Missing<state::BufferSize>,
1658 > {
1659 EnvironmentSpecBuilder {
1660 spec: Default::default(),
1661 marker: PhantomData,
1662 }
1663 }
1664}
1665
1666#[allow(clippy::type_complexity)]
1668#[must_use]
1669pub struct EnvironmentSpecBuilder<F, A, B, H, T, BN, NTER, TBAPI, PAPI, BS>
1670where
1671 F: Form,
1672 TypeSpec<F>: Default,
1673 EnvironmentSpec<F>: Default,
1674{
1675 spec: EnvironmentSpec<F>,
1676 marker: PhantomData<fn() -> (A, B, H, T, BN, NTER, TBAPI, PAPI, BS)>,
1677}
1678
1679impl<F, B, H, T, BN, NTER, TBAPI, PAPI, BS>
1680 EnvironmentSpecBuilder<
1681 F,
1682 Missing<state::AccountId>,
1683 B,
1684 H,
1685 T,
1686 BN,
1687 NTER,
1688 TBAPI,
1689 PAPI,
1690 BS,
1691 >
1692where
1693 F: Form,
1694 TypeSpec<F>: Default,
1695 EnvironmentSpec<F>: Default,
1696{
1697 pub fn account_id(
1699 self,
1700 account_id: TypeSpec<F>,
1701 ) -> EnvironmentSpecBuilder<F, state::AccountId, B, H, T, BN, NTER, TBAPI, PAPI, BS>
1702 {
1703 EnvironmentSpecBuilder {
1704 spec: EnvironmentSpec {
1705 account_id,
1706 ..self.spec
1707 },
1708 marker: PhantomData,
1709 }
1710 }
1711}
1712
1713impl<F, A, H, T, BN, NTER, TBAPI, PAPI, BS>
1714 EnvironmentSpecBuilder<F, A, Missing<state::Balance>, H, T, BN, NTER, TBAPI, PAPI, BS>
1715where
1716 F: Form,
1717 TypeSpec<F>: Default,
1718 EnvironmentSpec<F>: Default,
1719{
1720 pub fn balance(
1722 self,
1723 balance: TypeSpec<F>,
1724 ) -> EnvironmentSpecBuilder<F, A, state::Balance, H, T, BN, NTER, TBAPI, PAPI, BS>
1725 {
1726 EnvironmentSpecBuilder {
1727 spec: EnvironmentSpec {
1728 balance,
1729 ..self.spec
1730 },
1731 marker: PhantomData,
1732 }
1733 }
1734}
1735
1736impl<F, A, B, T, BN, NTER, TBAPI, PAPI, BS>
1737 EnvironmentSpecBuilder<F, A, B, Missing<state::Hash>, T, BN, NTER, TBAPI, PAPI, BS>
1738where
1739 F: Form,
1740 TypeSpec<F>: Default,
1741 EnvironmentSpec<F>: Default,
1742{
1743 pub fn hash(
1745 self,
1746 hash: TypeSpec<F>,
1747 ) -> EnvironmentSpecBuilder<F, A, B, state::Hash, T, BN, NTER, TBAPI, PAPI, BS> {
1748 EnvironmentSpecBuilder {
1749 spec: EnvironmentSpec { hash, ..self.spec },
1750 marker: PhantomData,
1751 }
1752 }
1753}
1754
1755impl<F, A, B, H, BN, NTER, TBAPI, PAPI, BS>
1756 EnvironmentSpecBuilder<
1757 F,
1758 A,
1759 B,
1760 H,
1761 Missing<state::Timestamp>,
1762 BN,
1763 NTER,
1764 TBAPI,
1765 PAPI,
1766 BS,
1767 >
1768where
1769 F: Form,
1770 TypeSpec<F>: Default,
1771 EnvironmentSpec<F>: Default,
1772{
1773 pub fn timestamp(
1775 self,
1776 timestamp: TypeSpec<F>,
1777 ) -> EnvironmentSpecBuilder<F, A, B, H, state::Timestamp, BN, NTER, TBAPI, PAPI, BS>
1778 {
1779 EnvironmentSpecBuilder {
1780 spec: EnvironmentSpec {
1781 timestamp,
1782 ..self.spec
1783 },
1784 marker: PhantomData,
1785 }
1786 }
1787}
1788
1789impl<F, A, B, H, T, NTER, TBAPI, PAPI, BS>
1790 EnvironmentSpecBuilder<
1791 F,
1792 A,
1793 B,
1794 H,
1795 T,
1796 Missing<state::BlockNumber>,
1797 NTER,
1798 TBAPI,
1799 PAPI,
1800 BS,
1801 >
1802where
1803 F: Form,
1804 TypeSpec<F>: Default,
1805 EnvironmentSpec<F>: Default,
1806{
1807 pub fn block_number(
1809 self,
1810 block_number: TypeSpec<F>,
1811 ) -> EnvironmentSpecBuilder<F, A, B, H, T, state::BlockNumber, NTER, TBAPI, PAPI, BS>
1812 {
1813 EnvironmentSpecBuilder {
1814 spec: EnvironmentSpec {
1815 block_number,
1816 ..self.spec
1817 },
1818 marker: PhantomData,
1819 }
1820 }
1821}
1822
1823impl<F, A, B, H, T, BN, PBAPI, PAPI, BS>
1824 EnvironmentSpecBuilder<
1825 F,
1826 A,
1827 B,
1828 H,
1829 T,
1830 BN,
1831 Missing<state::NativeToEthRatio>,
1832 PBAPI,
1833 PAPI,
1834 BS,
1835 >
1836where
1837 F: Form,
1838 TypeSpec<F>: Default,
1839 EnvironmentSpec<F>: Default,
1840{
1841 pub fn native_to_eth_ratio(
1843 self,
1844 native_to_eth_ratio: u32,
1845 ) -> EnvironmentSpecBuilder<F, A, B, H, T, BN, state::NativeToEthRatio, PBAPI, PAPI, BS>
1846 {
1847 EnvironmentSpecBuilder {
1848 spec: EnvironmentSpec {
1849 native_to_eth_ratio,
1850 ..self.spec
1851 },
1852 marker: PhantomData,
1853 }
1854 }
1855}
1856
1857impl<F, A, B, H, T, BN, NTER, PAPI, BS>
1858 EnvironmentSpecBuilder<
1859 F,
1860 A,
1861 B,
1862 H,
1863 T,
1864 BN,
1865 NTER,
1866 Missing<state::TrustBackedAssetsPrecompileIndex>,
1867 PAPI,
1868 BS,
1869 >
1870where
1871 F: Form,
1872 TypeSpec<F>: Default,
1873 EnvironmentSpec<F>: Default,
1874{
1875 pub fn trust_backed_assets_precompile_index(
1877 self,
1878 trust_backed_assets_precompile_index: u16,
1879 ) -> EnvironmentSpecBuilder<
1880 F,
1881 A,
1882 B,
1883 H,
1884 T,
1885 BN,
1886 NTER,
1887 state::TrustBackedAssetsPrecompileIndex,
1888 PAPI,
1889 BS,
1890 > {
1891 EnvironmentSpecBuilder {
1892 spec: EnvironmentSpec {
1893 trust_backed_assets_precompile_index,
1894 ..self.spec
1895 },
1896 marker: PhantomData,
1897 }
1898 }
1899}
1900
1901impl<F, A, B, H, T, BN, NTER, TBAPI, BS>
1902 EnvironmentSpecBuilder<
1903 F,
1904 A,
1905 B,
1906 H,
1907 T,
1908 BN,
1909 NTER,
1910 TBAPI,
1911 Missing<state::PoolAssetsPrecompileIndex>,
1912 BS,
1913 >
1914where
1915 F: Form,
1916 TypeSpec<F>: Default,
1917 EnvironmentSpec<F>: Default,
1918{
1919 pub fn pool_assets_precompile_index(
1921 self,
1922 pool_assets_precompile_index: u16,
1923 ) -> EnvironmentSpecBuilder<
1924 F,
1925 A,
1926 B,
1927 H,
1928 T,
1929 BN,
1930 NTER,
1931 TBAPI,
1932 state::PoolAssetsPrecompileIndex,
1933 BS,
1934 > {
1935 EnvironmentSpecBuilder {
1936 spec: EnvironmentSpec {
1937 pool_assets_precompile_index,
1938 ..self.spec
1939 },
1940 marker: PhantomData,
1941 }
1942 }
1943}
1944
1945impl<F, A, B, H, T, BN, NTER, TBAPI, PAPI>
1946 EnvironmentSpecBuilder<
1947 F,
1948 A,
1949 B,
1950 H,
1951 T,
1952 BN,
1953 NTER,
1954 TBAPI,
1955 PAPI,
1956 Missing<state::BufferSize>,
1957 >
1958where
1959 F: Form,
1960 TypeSpec<F>: Default,
1961 EnvironmentSpec<F>: Default,
1962{
1963 pub fn static_buffer_size(
1965 self,
1966 static_buffer_size: usize,
1967 ) -> EnvironmentSpecBuilder<F, A, B, H, T, BN, NTER, TBAPI, PAPI, state::BufferSize>
1968 {
1969 EnvironmentSpecBuilder {
1970 spec: EnvironmentSpec {
1971 static_buffer_size,
1972 ..self.spec
1973 },
1974 marker: PhantomData,
1975 }
1976 }
1977}
1978
1979impl<F>
1980 EnvironmentSpecBuilder<
1981 F,
1982 state::AccountId,
1983 state::Balance,
1984 state::Hash,
1985 state::Timestamp,
1986 state::BlockNumber,
1987 state::NativeToEthRatio,
1988 state::TrustBackedAssetsPrecompileIndex,
1989 state::PoolAssetsPrecompileIndex,
1990 state::BufferSize,
1991 >
1992where
1993 F: Form,
1994 TypeSpec<F>: Default,
1995 EnvironmentSpec<F>: Default,
1996{
1997 pub fn done(self) -> EnvironmentSpec<F> {
1999 self.spec
2000 }
2001}