ink_metadata/
specs.rs

1// Copyright (C) Use Ink (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![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/// Describes a contract.
61#[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    /// The set of constructors of the contract.
71    constructors: Vec<ConstructorSpec<F>>,
72    /// The external messages of the contract.
73    messages: Vec<MessageSpec<F>>,
74    /// The events of the contract.
75    events: Vec<EventSpec<F>>,
76    /// The contract documentation.
77    docs: Vec<F::String>,
78    /// The language specific error type.
79    lang_error: TypeSpec<F>,
80    /// The environment types of the contract specification.
81    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    /// Returns the set of constructors of the contract.
117    pub fn constructors(&self) -> &[ConstructorSpec<F>] {
118        &self.constructors
119    }
120
121    /// Returns the external messages of the contract.
122    pub fn messages(&self) -> &[MessageSpec<F>] {
123        &self.messages
124    }
125
126    /// Returns the events of the contract.
127    pub fn events(&self) -> &[EventSpec<F>] {
128        &self.events
129    }
130
131    /// Returns the contract documentation.
132    pub fn docs(&self) -> &[F::String] {
133        &self.docs
134    }
135
136    /// Returns the language error type.
137    pub fn lang_error(&self) -> &TypeSpec<F> {
138        &self.lang_error
139    }
140    // Returns the environment types of the contract specification.
141    pub fn environment(&self) -> &EnvironmentSpec<F> {
142        &self.environment
143    }
144}
145
146/// The message builder is ready to finalize construction.
147pub enum Valid {}
148/// The message builder is not ready to finalize construction.
149pub enum Invalid {}
150
151#[must_use]
152pub struct ContractSpecBuilder<F, S = Invalid>
153where
154    F: Form,
155    TypeSpec<F>: Default,
156{
157    /// The to-be-constructed contract specification.
158    spec: ContractSpec<F>,
159    /// Marker for compile-time checking of valid contract specifications.
160    marker: PhantomData<fn() -> S>,
161}
162
163impl<F> ContractSpecBuilder<F, Invalid>
164where
165    F: Form,
166    TypeSpec<F>: Default,
167{
168    /// Sets the constructors of the contract specification.
169    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    /// Sets the messages of the contract specification.
190    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    /// Sets the events of the contract specification.
205    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    /// Sets the documentation of the contract specification.
220    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    /// Sets the language error of the contract specification.
235    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    /// Sets the environment types of the contract specification.
246    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    /// Finalizes construction of the contract specification.
264    #[allow(clippy::arithmetic_side_effects)] // todo
265    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    /// Creates a new contract specification.
347    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/// Describes a constructor of a contract.
363#[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    /// The label of the constructor.
371    ///
372    /// In case of a trait provided constructor the label is prefixed with the trait
373    /// label.
374    pub label: F::String,
375    /// The selector hash of the message.
376    pub selector: Selector,
377    /// If the constructor accepts any `value` from the caller.
378    pub payable: bool,
379    /// The parameters of the deployment handler.
380    pub args: Vec<MessageParamSpec<F>>,
381    /// The return type of the constructor..
382    pub return_type: ReturnTypeSpec<F>,
383    /// The deployment handler documentation.
384    pub docs: Vec<F::String>,
385    /// If the constructor is the default for off-chain consumers (e.g UIs).
386    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    /// Returns the label of the constructor.
414    ///
415    /// In case of a trait provided constructor the label is prefixed with the trait
416    /// label.
417    pub fn label(&self) -> &F::String {
418        &self.label
419    }
420
421    /// Returns the selector hash of the constructor.
422    pub fn selector(&self) -> &Selector {
423        &self.selector
424    }
425
426    /// Returns if the constructor is payable by the caller.
427    pub fn payable(&self) -> bool {
428        self.payable
429    }
430
431    /// Returns the parameters of the deployment handler.
432    pub fn args(&self) -> &[MessageParamSpec<F>] {
433        &self.args
434    }
435
436    /// Returns the return type of the constructor.
437    pub fn return_type(&self) -> &ReturnTypeSpec<F> {
438        &self.return_type
439    }
440
441    /// Returns the deployment handler documentation.
442    pub fn docs(&self) -> &[F::String] {
443        &self.docs
444    }
445
446    pub fn default(&self) -> bool {
447        self.default
448    }
449}
450
451/// A builder for constructors.
452///
453/// # Developer Note
454///
455/// Some fields are guarded by a type-state pattern to fail at
456/// compile-time instead of at run-time. This is useful to better
457/// debug code-gen macros.
458#[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    /// Creates a new constructor spec builder.
471    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    /// Sets the function selector of the message.
499    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    /// Sets if the constructor is payable, thus accepting value for the caller.
518    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    /// Sets the return type of the constructor.
537    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    /// Sets the input arguments of the constructor specification.
556    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    /// Sets the documentation of the constructor specification.
567    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    /// Sets the default of the constructor specification.
582    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    /// Finishes construction of the constructor.
598    pub fn done(self) -> ConstructorSpec<F> {
599        self.spec
600    }
601}
602
603/// Describes a contract message.
604#[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    /// The label of the message.
612    ///
613    /// In case of trait provided messages and constructors the prefix
614    /// by convention in ink! is the label of the trait.
615    label: F::String,
616    /// The selector hash of the message.
617    selector: Selector,
618    /// If the message is allowed to mutate the contract state.
619    mutates: bool,
620    /// If the message accepts any `value` from the caller.
621    payable: bool,
622    /// The parameters of the message.
623    args: Vec<MessageParamSpec<F>>,
624    /// The return type of the message.
625    return_type: ReturnTypeSpec<F>,
626    /// The message documentation.
627    docs: Vec<F::String>,
628    /// If the message is the default for off-chain consumers (e.g UIs).
629    default: bool,
630}
631
632/// Type state for builders to tell that some mandatory state has not yet been set
633/// yet or to fail upon setting the same state multiple times.
634pub struct Missing<S>(PhantomData<fn() -> S>);
635
636mod state {
637    //! Type states that tell what state of a message has not
638    //! yet been set properly for a valid construction.
639
640    /// Type state for the message selector of a message.
641    pub struct Selector;
642    /// Type state for the mutability of a message.
643    pub struct Mutates;
644    /// Type state for telling if the message is payable.
645    pub struct IsPayable;
646    /// Type state for the message return type.
647    pub struct Returns;
648    /// Type state for the `AccountId` type of the environment.
649    pub struct AccountId;
650    /// Type state for the `Balance` type of the environment.
651    pub struct Balance;
652    /// Type state for the `Hash` type of the environment.
653    pub struct Hash;
654    /// Type state for the `Timestamp` type of the environment.
655    pub struct Timestamp;
656    /// Type state for the `BlockNumber` type of the environment.
657    pub struct BlockNumber;
658    /// Type state for the native to eth ratio specified in the environment.
659    pub struct NativeToEthRatio;
660    /// Type state for the size of the static buffer configured via environment variable.`
661    pub struct BufferSize;
662}
663
664impl<F> MessageSpec<F>
665where
666    F: Form,
667    TypeSpec<F>: Default,
668{
669    /// Creates a new message spec builder.
670    pub fn from_label(
671        label: <F as Form>::String,
672    ) -> MessageSpecBuilder<
673        F,
674        Missing<state::Selector>,
675        Missing<state::Mutates>,
676        Missing<state::IsPayable>,
677        Missing<state::Returns>,
678    > {
679        MessageSpecBuilder {
680            spec: Self {
681                label,
682                selector: Selector::default(),
683                mutates: false,
684                payable: false,
685                args: Vec::new(),
686                return_type: ReturnTypeSpec::new(TypeSpec::default()),
687                docs: Vec::new(),
688                default: false,
689            },
690            marker: PhantomData,
691        }
692    }
693}
694
695impl<F> MessageSpec<F>
696where
697    F: Form,
698{
699    /// Returns the label of the message.
700    ///
701    /// In case of trait provided messages and constructors the prefix
702    /// by convention in ink! is the label of the trait.
703    pub fn label(&self) -> &F::String {
704        &self.label
705    }
706
707    /// Returns the selector hash of the message.
708    pub fn selector(&self) -> &Selector {
709        &self.selector
710    }
711
712    /// Returns true if the message is allowed to mutate the contract state.
713    pub fn mutates(&self) -> bool {
714        self.mutates
715    }
716
717    /// Returns true if the message is payable by the caller.
718    pub fn payable(&self) -> bool {
719        self.payable
720    }
721
722    /// Returns the parameters of the message.
723    pub fn args(&self) -> &[MessageParamSpec<F>] {
724        &self.args
725    }
726
727    /// Returns the return type of the message.
728    pub fn return_type(&self) -> &ReturnTypeSpec<F> {
729        &self.return_type
730    }
731
732    /// Returns the message documentation.
733    pub fn docs(&self) -> &[F::String] {
734        &self.docs
735    }
736
737    pub fn default(&self) -> bool {
738        self.default
739    }
740}
741
742/// A builder for messages.
743///
744/// # Developer Note
745///
746/// Some fields are guarded by a type-state pattern to fail at
747/// compile-time instead of at run-time. This is useful to better
748/// debug code-gen macros.
749#[allow(clippy::type_complexity)]
750#[must_use]
751pub struct MessageSpecBuilder<F, Selector, Mutates, IsPayable, Returns>
752where
753    F: Form,
754{
755    spec: MessageSpec<F>,
756    marker: PhantomData<fn() -> (Selector, Mutates, IsPayable, Returns)>,
757}
758
759impl<F, M, P, R> MessageSpecBuilder<F, Missing<state::Selector>, M, P, R>
760where
761    F: Form,
762{
763    /// Sets the function selector of the message.
764    pub fn selector(
765        self,
766        selector: [u8; 4],
767    ) -> MessageSpecBuilder<F, state::Selector, M, P, R> {
768        MessageSpecBuilder {
769            spec: MessageSpec {
770                selector: selector.into(),
771                ..self.spec
772            },
773            marker: PhantomData,
774        }
775    }
776}
777
778impl<F, S, P, R> MessageSpecBuilder<F, S, Missing<state::Mutates>, P, R>
779where
780    F: Form,
781{
782    /// Sets if the message is mutable, thus taking `&mut self` or not thus taking
783    /// `&self`.
784    pub fn mutates(
785        self,
786        mutates: bool,
787    ) -> MessageSpecBuilder<F, S, state::Mutates, P, R> {
788        MessageSpecBuilder {
789            spec: MessageSpec {
790                mutates,
791                ..self.spec
792            },
793            marker: PhantomData,
794        }
795    }
796}
797
798impl<F, S, M, R> MessageSpecBuilder<F, S, M, Missing<state::IsPayable>, R>
799where
800    F: Form,
801{
802    /// Sets if the message is payable, thus accepting value for the caller.
803    pub fn payable(
804        self,
805        is_payable: bool,
806    ) -> MessageSpecBuilder<F, S, M, state::IsPayable, R> {
807        MessageSpecBuilder {
808            spec: MessageSpec {
809                payable: is_payable,
810                ..self.spec
811            },
812            marker: PhantomData,
813        }
814    }
815}
816
817impl<F, M, S, P> MessageSpecBuilder<F, S, M, P, Missing<state::Returns>>
818where
819    F: Form,
820{
821    /// Sets the return type of the message.
822    pub fn returns(
823        self,
824        return_type: ReturnTypeSpec<F>,
825    ) -> MessageSpecBuilder<F, S, M, P, state::Returns> {
826        MessageSpecBuilder {
827            spec: MessageSpec {
828                return_type,
829                ..self.spec
830            },
831            marker: PhantomData,
832        }
833    }
834}
835
836impl<F, S, M, P, R> MessageSpecBuilder<F, S, M, P, R>
837where
838    F: Form,
839{
840    /// Sets the input arguments of the message specification.
841    pub fn args<A>(self, args: A) -> Self
842    where
843        A: IntoIterator<Item = MessageParamSpec<F>>,
844    {
845        let mut this = self;
846        debug_assert!(this.spec.args.is_empty());
847        this.spec.args = args.into_iter().collect::<Vec<_>>();
848        this
849    }
850
851    /// Sets the documentation of the message specification.
852    pub fn docs<D>(self, docs: D) -> Self
853    where
854        D: IntoIterator<Item = <F as Form>::String>,
855    {
856        let mut this = self;
857        debug_assert!(this.spec.docs.is_empty());
858        this.spec.docs = docs.into_iter().collect::<Vec<_>>();
859        this
860    }
861
862    /// Sets the default of the message specification.
863    pub fn default(self, default: bool) -> Self {
864        MessageSpecBuilder {
865            spec: MessageSpec {
866                default,
867                ..self.spec
868            },
869            marker: PhantomData,
870        }
871    }
872}
873
874impl<F>
875    MessageSpecBuilder<
876        F,
877        state::Selector,
878        state::Mutates,
879        state::IsPayable,
880        state::Returns,
881    >
882where
883    F: Form,
884{
885    /// Finishes construction of the message.
886    pub fn done(self) -> MessageSpec<F> {
887        self.spec
888    }
889}
890
891impl IntoPortable for MessageSpec {
892    type Output = MessageSpec<PortableForm>;
893
894    fn into_portable(self, registry: &mut Registry) -> Self::Output {
895        MessageSpec {
896            label: self.label.to_string(),
897            selector: self.selector,
898            mutates: self.mutates,
899            payable: self.payable,
900            default: self.default,
901            args: self
902                .args
903                .into_iter()
904                .map(|arg| arg.into_portable(registry))
905                .collect::<Vec<_>>(),
906            return_type: self.return_type.into_portable(registry),
907            docs: self.docs.into_iter().map(|s| s.into()).collect(),
908        }
909    }
910}
911
912/// Describes an event definition.
913#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
914#[serde(bound(
915    serialize = "F::Type: Serialize, F::String: Serialize",
916    deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
917))]
918pub struct EventSpec<F: Form = MetaForm> {
919    /// The label of the event.
920    label: F::String,
921    /// The module path to the event type definition.
922    module_path: F::String,
923    /// The signature topic of the event. `None` if the event is anonymous.
924    signature_topic: Option<SignatureTopic>,
925    /// The event arguments.
926    args: Vec<EventParamSpec<F>>,
927    /// The event documentation.
928    docs: Vec<F::String>,
929}
930
931/// The value of the signature topic for a non anonymous event.
932#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
933#[serde(transparent)]
934pub struct SignatureTopic {
935    #[serde(
936        serialize_with = "serialize_as_byte_str",
937        deserialize_with = "deserialize_from_byte_str"
938    )]
939    bytes: Vec<u8>,
940}
941
942impl<T> From<T> for SignatureTopic
943where
944    T: AsRef<[u8]>,
945{
946    fn from(bytes: T) -> Self {
947        SignatureTopic {
948            bytes: bytes.as_ref().to_vec(),
949        }
950    }
951}
952
953impl SignatureTopic {
954    /// Returns the bytes of the signature topic.
955    pub fn as_bytes(&self) -> &[u8] {
956        &self.bytes
957    }
958}
959
960/// An event specification builder.
961#[must_use]
962pub struct EventSpecBuilder<F>
963where
964    F: Form,
965{
966    spec: EventSpec<F>,
967}
968
969impl<F> EventSpecBuilder<F>
970where
971    F: Form,
972{
973    /// Sets the module path to the event type definition.
974    pub fn module_path<'a>(self, path: &'a str) -> Self
975    where
976        F::String: From<&'a str>,
977    {
978        let mut this = self;
979        this.spec.module_path = path.into();
980        this
981    }
982
983    /// Sets the input arguments of the event specification.
984    pub fn args<A>(self, args: A) -> Self
985    where
986        A: IntoIterator<Item = EventParamSpec<F>>,
987    {
988        let mut this = self;
989        debug_assert!(this.spec.args.is_empty());
990        this.spec.args = args.into_iter().collect::<Vec<_>>();
991        this
992    }
993
994    /// Sets the signature topic of the event specification.
995    pub fn signature_topic<T>(self, topic: Option<T>) -> Self
996    where
997        T: AsRef<[u8]>,
998    {
999        let mut this = self;
1000        debug_assert!(this.spec.signature_topic.is_none());
1001        this.spec.signature_topic = topic.as_ref().map(SignatureTopic::from);
1002        this
1003    }
1004
1005    /// Sets the input arguments of the event specification.
1006    pub fn docs<'a, D>(self, docs: D) -> Self
1007    where
1008        D: IntoIterator<Item = &'a str>,
1009        F::String: From<&'a str>,
1010    {
1011        let mut this = self;
1012        debug_assert!(this.spec.docs.is_empty());
1013        this.spec.docs = docs
1014            .into_iter()
1015            .map(|s| trim_extra_whitespace(s).into())
1016            .collect::<Vec<_>>();
1017        this
1018    }
1019
1020    /// Finalizes building the event specification.
1021    pub fn done(self) -> EventSpec<F> {
1022        self.spec
1023    }
1024}
1025
1026impl IntoPortable for EventSpec {
1027    type Output = EventSpec<PortableForm>;
1028
1029    fn into_portable(self, registry: &mut Registry) -> Self::Output {
1030        EventSpec {
1031            label: self.label.to_string(),
1032            module_path: self.module_path.to_string(),
1033            signature_topic: self.signature_topic,
1034            args: self
1035                .args
1036                .into_iter()
1037                .map(|arg| arg.into_portable(registry))
1038                .collect::<Vec<_>>(),
1039            docs: self.docs.into_iter().map(|s| s.into()).collect(),
1040        }
1041    }
1042}
1043
1044impl<F> EventSpec<F>
1045where
1046    F: Form,
1047    F::String: Default,
1048{
1049    /// Creates a new event specification builder.
1050    pub fn new(label: <F as Form>::String) -> EventSpecBuilder<F> {
1051        EventSpecBuilder {
1052            spec: Self {
1053                label,
1054                module_path: Default::default(),
1055                signature_topic: None,
1056                args: Vec::new(),
1057                docs: Vec::new(),
1058            },
1059        }
1060    }
1061}
1062
1063impl<F> EventSpec<F>
1064where
1065    F: Form,
1066{
1067    /// Returns the label of the event.
1068    pub fn label(&self) -> &F::String {
1069        &self.label
1070    }
1071
1072    /// The event arguments.
1073    pub fn args(&self) -> &[EventParamSpec<F>] {
1074        &self.args
1075    }
1076
1077    /// The signature topic of the event. `None` if the event is anonymous.
1078    pub fn signature_topic(&self) -> Option<&SignatureTopic> {
1079        self.signature_topic.as_ref()
1080    }
1081
1082    /// The event documentation.
1083    pub fn docs(&self) -> &[F::String] {
1084        &self.docs
1085    }
1086}
1087
1088/// The 4 byte selector to identify constructors and messages
1089#[cfg_attr(feature = "std", derive(Hash))]
1090#[derive(Debug, Default, PartialEq, Eq, derive_more::From, JsonSchema)]
1091pub struct Selector(#[schemars(with = "String")] [u8; 4]);
1092
1093impl serde::Serialize for Selector {
1094    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1095    where
1096        S: serde::Serializer,
1097    {
1098        serde_hex::serialize(&self.0, serializer)
1099    }
1100}
1101
1102impl<'de> serde::Deserialize<'de> for Selector {
1103    fn deserialize<D>(d: D) -> Result<Self, D::Error>
1104    where
1105        D: serde::Deserializer<'de>,
1106    {
1107        let mut arr = [0; 4];
1108        serde_hex::deserialize_check_len(d, serde_hex::ExpectedLen::Exact(&mut arr[..]))?;
1109        Ok(arr.into())
1110    }
1111}
1112
1113impl Selector {
1114    /// Create a new custom selector.
1115    pub fn new<T>(bytes: T) -> Self
1116    where
1117        T: Into<[u8; 4]>,
1118    {
1119        Self(bytes.into())
1120    }
1121
1122    /// Returns the underlying selector bytes.
1123    pub fn to_bytes(&self) -> &[u8] {
1124        &self.0
1125    }
1126}
1127
1128/// Describes the syntactical name of a type at a given type position.
1129///
1130/// This is important when trying to work with type aliases.
1131/// Normally a type alias is transparent and so scenarios such as
1132/// ```no_compile
1133/// type Foo = i32;
1134/// fn bar(foo: Foo);
1135/// ```
1136/// Will only communicate that `foo` is of type `i32` which is correct,
1137/// however, it will miss the potentially important information that it
1138/// is being used through a type alias named `Foo`.
1139///
1140/// In ink! we currently experience this problem with environmental types
1141/// such as the `Balance` type that is just a type alias to `u128` in the
1142/// default setup. Even though it would be useful for third party tools
1143/// such as the Polkadot UI to know that we are handling with `Balance`
1144/// types, we currently cannot communicate this without display names.
1145pub type DisplayName<F> = scale_info::Path<F>;
1146
1147/// A type specification.
1148///
1149/// This contains the actual type as well as an optional compile-time
1150/// known displayed representation of the type. This is useful for cases
1151/// where the type is used through a type alias in order to provide
1152/// information about the alias name.
1153///
1154/// # Examples
1155///
1156/// Consider the following Rust function:
1157/// ```no_compile
1158/// fn is_sorted(input: &[i32], pred: Predicate) -> bool;
1159/// ```
1160/// In this above example `input` would have no displayable name,
1161/// `pred`s display name is `Predicate` and the display name of
1162/// the return type is simply `bool`. Note that `Predicate` could
1163/// simply be a type alias to `fn(i32, i32) -> Ordering`.
1164#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1165#[serde(bound(
1166    serialize = "F::Type: Serialize, F::String: Serialize",
1167    deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1168))]
1169#[serde(rename_all = "camelCase")]
1170pub struct TypeSpec<F: Form = MetaForm> {
1171    /// The actual type.
1172    #[serde(rename = "type")]
1173    ty: F::Type,
1174    /// The compile-time known displayed representation of the type.
1175    display_name: DisplayName<F>,
1176}
1177
1178impl Default for TypeSpec<MetaForm> {
1179    fn default() -> Self {
1180        TypeSpec::of_type::<()>()
1181    }
1182}
1183
1184impl Default for TypeSpec<PortableForm> {
1185    fn default() -> Self {
1186        Self {
1187            ty: u32::default().into(),
1188            display_name: Default::default(),
1189        }
1190    }
1191}
1192
1193impl IntoPortable for TypeSpec {
1194    type Output = TypeSpec<PortableForm>;
1195
1196    fn into_portable(self, registry: &mut Registry) -> Self::Output {
1197        TypeSpec {
1198            ty: registry.register_type(&self.ty),
1199            display_name: self.display_name.into_portable(registry),
1200        }
1201    }
1202}
1203
1204impl TypeSpec {
1205    /// Creates a new type specification with a display name.
1206    ///
1207    /// The name is any valid Rust identifier or path.
1208    ///
1209    /// # Examples
1210    ///
1211    /// Valid display names are `foo`, `foo::bar`, `foo::bar::Baz`, etc.
1212    ///
1213    /// # Panics
1214    ///
1215    /// Panics if the given display name is invalid.
1216    pub fn with_name_str<T>(display_name: &'static str) -> Self
1217    where
1218        T: TypeInfo + 'static,
1219    {
1220        Self::with_name_segs::<T, _>(display_name.split("::"))
1221    }
1222
1223    /// Creates a new type specification with a display name
1224    /// represented by the given path segments.
1225    ///
1226    /// The display name segments all must be valid Rust identifiers.
1227    ///
1228    /// # Examples
1229    ///
1230    /// Valid display names are `foo`, `foo::bar`, `foo::bar::Baz`, etc.
1231    ///
1232    /// # Panics
1233    ///
1234    /// Panics if the given display name is invalid.
1235    pub fn with_name_segs<T, S>(segments: S) -> Self
1236    where
1237        T: TypeInfo + 'static,
1238        S: IntoIterator<Item = &'static str>,
1239    {
1240        Self {
1241            ty: meta_type::<T>(),
1242            display_name: DisplayName::from_segments(segments)
1243                .unwrap_or_else(|err| panic!("display name is invalid: {err:?}")),
1244        }
1245    }
1246
1247    /// Creates a new type specification without a display name.
1248    ///
1249    /// Example:
1250    /// ```no_run
1251    /// # use ink_metadata::{TypeSpec, ReturnTypeSpec};
1252    /// ReturnTypeSpec::new(TypeSpec::of_type::<i32>()); // return type of `i32`
1253    /// ```
1254    pub fn of_type<T>() -> Self
1255    where
1256        T: TypeInfo + 'static,
1257    {
1258        Self {
1259            ty: meta_type::<T>(),
1260            display_name: DisplayName::default(),
1261        }
1262    }
1263}
1264
1265impl<F> TypeSpec<F>
1266where
1267    F: Form,
1268{
1269    /// Returns the actual type.
1270    pub fn ty(&self) -> &F::Type {
1271        &self.ty
1272    }
1273
1274    /// Returns the compile-time known displayed representation of the type.
1275    pub fn display_name(&self) -> &DisplayName<F> {
1276        &self.display_name
1277    }
1278
1279    /// Creates a new type specification for a given type and display name.
1280    pub fn new(ty: <F as Form>::Type, display_name: DisplayName<F>) -> Self {
1281        Self { ty, display_name }
1282    }
1283}
1284
1285/// Describes a pair of parameter label and type.
1286#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1287#[serde(bound(
1288    serialize = "F::Type: Serialize, F::String: Serialize",
1289    deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1290))]
1291pub struct EventParamSpec<F: Form = MetaForm> {
1292    /// The label of the parameter.
1293    label: F::String,
1294    /// If the event parameter is indexed as a topic.
1295    indexed: bool,
1296    /// The type of the parameter.
1297    #[serde(rename = "type")]
1298    ty: TypeSpec<F>,
1299    /// The documentation associated with the arguments.
1300    docs: Vec<F::String>,
1301}
1302
1303impl IntoPortable for EventParamSpec {
1304    type Output = EventParamSpec<PortableForm>;
1305
1306    fn into_portable(self, registry: &mut Registry) -> Self::Output {
1307        EventParamSpec {
1308            label: self.label.to_string(),
1309            indexed: self.indexed,
1310            ty: self.ty.into_portable(registry),
1311            docs: self.docs.into_iter().map(|s| s.into()).collect(),
1312        }
1313    }
1314}
1315
1316impl<F> EventParamSpec<F>
1317where
1318    F: Form,
1319    TypeSpec<F>: Default,
1320{
1321    /// Creates a new event parameter specification builder.
1322    pub fn new(label: F::String) -> EventParamSpecBuilder<F> {
1323        EventParamSpecBuilder {
1324            spec: Self {
1325                label,
1326                // By default event parameters are not indexed as topics.
1327                indexed: false,
1328                // We initialize every parameter type as `()`.
1329                ty: Default::default(),
1330                // We start with empty docs.
1331                docs: vec![],
1332            },
1333        }
1334    }
1335    /// Returns the label of the parameter.
1336    pub fn label(&self) -> &F::String {
1337        &self.label
1338    }
1339
1340    /// Returns true if the event parameter is indexed as a topic.
1341    pub fn indexed(&self) -> bool {
1342        self.indexed
1343    }
1344
1345    /// Returns the type of the parameter.
1346    pub fn ty(&self) -> &TypeSpec<F> {
1347        &self.ty
1348    }
1349
1350    /// Returns the documentation associated with the arguments.
1351    pub fn docs(&self) -> &[F::String] {
1352        &self.docs
1353    }
1354}
1355
1356/// Used to construct an event parameter specification.
1357#[must_use]
1358pub struct EventParamSpecBuilder<F>
1359where
1360    F: Form,
1361{
1362    /// The built-up event parameter specification.
1363    spec: EventParamSpec<F>,
1364}
1365
1366impl<F> EventParamSpecBuilder<F>
1367where
1368    F: Form,
1369{
1370    /// Sets the type of the event parameter.
1371    pub fn of_type(self, spec: TypeSpec<F>) -> Self {
1372        let mut this = self;
1373        this.spec.ty = spec;
1374        this
1375    }
1376
1377    /// If the event parameter is indexed as a topic.
1378    pub fn indexed(self, is_indexed: bool) -> Self {
1379        let mut this = self;
1380        this.spec.indexed = is_indexed;
1381        this
1382    }
1383
1384    /// Sets the documentation of the event parameter.
1385    pub fn docs<'a, D>(self, docs: D) -> Self
1386    where
1387        D: IntoIterator<Item = &'a str>,
1388        F::String: From<&'a str>,
1389    {
1390        debug_assert!(self.spec.docs.is_empty());
1391        Self {
1392            spec: EventParamSpec {
1393                docs: docs
1394                    .into_iter()
1395                    .map(|s| trim_extra_whitespace(s).into())
1396                    .collect::<Vec<_>>(),
1397                ..self.spec
1398            },
1399        }
1400    }
1401
1402    /// Finishes constructing the event parameter spec.
1403    pub fn done(self) -> EventParamSpec<F> {
1404        self.spec
1405    }
1406}
1407
1408/// Describes the contract message return type.
1409#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1410#[serde(transparent)]
1411#[serde(bound(
1412    serialize = "F::Type: Serialize, F::String: Serialize",
1413    deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1414))]
1415#[must_use]
1416pub struct ReturnTypeSpec<F: Form = MetaForm> {
1417    #[serde(rename = "type")]
1418    ret_type: TypeSpec<F>,
1419}
1420
1421impl IntoPortable for ReturnTypeSpec {
1422    type Output = ReturnTypeSpec<PortableForm>;
1423
1424    fn into_portable(self, registry: &mut Registry) -> Self::Output {
1425        ReturnTypeSpec {
1426            ret_type: self.ret_type.into_portable(registry),
1427        }
1428    }
1429}
1430
1431impl<F> ReturnTypeSpec<F>
1432where
1433    F: Form,
1434    TypeSpec<F>: Default,
1435{
1436    /// Creates a new return type specification from the given type or `None`.
1437    ///
1438    /// # Examples
1439    ///
1440    /// ```no_run
1441    /// # use ink_metadata::{TypeSpec, ReturnTypeSpec};
1442    /// <ReturnTypeSpec<scale_info::form::MetaForm>>::new(TypeSpec::default()); // no return type;
1443    /// ```
1444    pub fn new<T>(ty: T) -> Self
1445    where
1446        T: Into<TypeSpec<F>>,
1447    {
1448        Self {
1449            ret_type: ty.into(),
1450        }
1451    }
1452
1453    /// Returns the return type
1454    pub fn ret_type(&self) -> &TypeSpec<F> {
1455        &self.ret_type
1456    }
1457}
1458
1459/// Describes a pair of parameter label and type.
1460#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1461#[serde(bound(
1462    serialize = "F::Type: Serialize, F::String: Serialize",
1463    deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1464))]
1465pub struct MessageParamSpec<F: Form = MetaForm> {
1466    /// The label of the parameter.
1467    label: F::String,
1468    /// The type of the parameter.
1469    #[serde(rename = "type")]
1470    ty: TypeSpec<F>,
1471}
1472
1473impl IntoPortable for MessageParamSpec {
1474    type Output = MessageParamSpec<PortableForm>;
1475
1476    fn into_portable(self, registry: &mut Registry) -> Self::Output {
1477        MessageParamSpec {
1478            label: self.label.to_string(),
1479            ty: self.ty.into_portable(registry),
1480        }
1481    }
1482}
1483
1484impl<F> MessageParamSpec<F>
1485where
1486    F: Form,
1487    TypeSpec<F>: Default,
1488{
1489    /// Constructs a new message parameter specification via builder.
1490    pub fn new(label: F::String) -> MessageParamSpecBuilder<F> {
1491        MessageParamSpecBuilder {
1492            spec: Self {
1493                label,
1494                // Uses `()` type by default.
1495                ty: TypeSpec::default(),
1496            },
1497        }
1498    }
1499
1500    /// Returns the label of the parameter.
1501    pub fn label(&self) -> &F::String {
1502        &self.label
1503    }
1504
1505    /// Returns the type of the parameter.
1506    pub fn ty(&self) -> &TypeSpec<F> {
1507        &self.ty
1508    }
1509}
1510
1511/// Used to construct a message parameter specification.
1512#[must_use]
1513pub struct MessageParamSpecBuilder<F: Form> {
1514    /// The to-be-constructed message parameter specification.
1515    spec: MessageParamSpec<F>,
1516}
1517
1518impl<F> MessageParamSpecBuilder<F>
1519where
1520    F: Form,
1521{
1522    /// Sets the type of the message parameter.
1523    pub fn of_type(self, ty: TypeSpec<F>) -> Self {
1524        let mut this = self;
1525        this.spec.ty = ty;
1526        this
1527    }
1528
1529    /// Finishes construction of the message parameter.
1530    pub fn done(self) -> MessageParamSpec<F> {
1531        self.spec
1532    }
1533}
1534
1535/// Describes a contract environment.
1536#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
1537#[serde(bound(
1538    serialize = "F::Type: Serialize, F::String: Serialize",
1539    deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
1540))]
1541#[serde(rename_all = "camelCase")]
1542pub struct EnvironmentSpec<F: Form = MetaForm>
1543where
1544    TypeSpec<F>: Default,
1545{
1546    account_id: TypeSpec<F>,
1547    balance: TypeSpec<F>,
1548    hash: TypeSpec<F>,
1549    timestamp: TypeSpec<F>,
1550    block_number: TypeSpec<F>,
1551    native_to_eth_ratio: u32,
1552    static_buffer_size: usize,
1553}
1554
1555impl<F> Default for EnvironmentSpec<F>
1556where
1557    F: Form,
1558    TypeSpec<F>: Default,
1559{
1560    fn default() -> Self {
1561        Self {
1562            account_id: Default::default(),
1563            balance: Default::default(),
1564            hash: Default::default(),
1565            timestamp: Default::default(),
1566            block_number: Default::default(),
1567            native_to_eth_ratio: Default::default(),
1568            static_buffer_size: Default::default(),
1569        }
1570    }
1571}
1572
1573impl IntoPortable for EnvironmentSpec {
1574    type Output = EnvironmentSpec<PortableForm>;
1575
1576    fn into_portable(self, registry: &mut Registry) -> Self::Output {
1577        EnvironmentSpec {
1578            account_id: self.account_id.into_portable(registry),
1579            balance: self.balance.into_portable(registry),
1580            hash: self.hash.into_portable(registry),
1581            timestamp: self.timestamp.into_portable(registry),
1582            block_number: self.block_number.into_portable(registry),
1583            native_to_eth_ratio: self.native_to_eth_ratio,
1584            static_buffer_size: self.static_buffer_size,
1585        }
1586    }
1587}
1588
1589impl<F> EnvironmentSpec<F>
1590where
1591    F: Form,
1592    TypeSpec<F>: Default,
1593{
1594    /// Returns the `AccountId` type of the environment.
1595    pub fn account_id(&self) -> &TypeSpec<F> {
1596        &self.account_id
1597    }
1598    /// Returns the `Balance` type of the environment.
1599    pub fn balance(&self) -> &TypeSpec<F> {
1600        &self.balance
1601    }
1602    /// Returns the `Hash` type of the environment.
1603    pub fn hash(&self) -> &TypeSpec<F> {
1604        &self.hash
1605    }
1606    /// Returns the `Timestamp` type of the environment.
1607    pub fn timestamp(&self) -> &TypeSpec<F> {
1608        &self.timestamp
1609    }
1610    /// Returns the `BlockNumber` type of the environment.
1611    pub fn block_number(&self) -> &TypeSpec<F> {
1612        &self.block_number
1613    }
1614    /// Returns the `NATIVE_TO_ETH_RATIO` value of the environment.
1615    pub fn native_to_eth_ratio(&self) -> u32 {
1616        self.native_to_eth_ratio
1617    }
1618}
1619
1620#[allow(clippy::type_complexity)]
1621impl<F> EnvironmentSpec<F>
1622where
1623    F: Form,
1624    TypeSpec<F>: Default,
1625    EnvironmentSpec<F>: Default,
1626{
1627    pub fn new() -> EnvironmentSpecBuilder<
1628        F,
1629        Missing<state::AccountId>,
1630        Missing<state::Balance>,
1631        Missing<state::Hash>,
1632        Missing<state::Timestamp>,
1633        Missing<state::BlockNumber>,
1634        Missing<state::NativeToEthRatio>,
1635        Missing<state::BufferSize>,
1636    > {
1637        EnvironmentSpecBuilder {
1638            spec: Default::default(),
1639            marker: PhantomData,
1640        }
1641    }
1642}
1643
1644/// An environment specification builder.
1645#[allow(clippy::type_complexity)]
1646#[must_use]
1647pub struct EnvironmentSpecBuilder<F, A, B, H, T, BN, NTER, BS>
1648where
1649    F: Form,
1650    TypeSpec<F>: Default,
1651    EnvironmentSpec<F>: Default,
1652{
1653    spec: EnvironmentSpec<F>,
1654    marker: PhantomData<fn() -> (A, B, H, T, BN, NTER, BS)>,
1655}
1656
1657impl<F, B, H, T, BN, NTER, BS>
1658    EnvironmentSpecBuilder<F, Missing<state::AccountId>, B, H, T, BN, NTER, BS>
1659where
1660    F: Form,
1661    TypeSpec<F>: Default,
1662    EnvironmentSpec<F>: Default,
1663{
1664    /// Sets the `AccountId` type of the environment.
1665    pub fn account_id(
1666        self,
1667        account_id: TypeSpec<F>,
1668    ) -> EnvironmentSpecBuilder<F, state::AccountId, B, H, T, BN, NTER, BS> {
1669        EnvironmentSpecBuilder {
1670            spec: EnvironmentSpec {
1671                account_id,
1672                ..self.spec
1673            },
1674            marker: PhantomData,
1675        }
1676    }
1677}
1678
1679impl<F, A, H, T, BN, NTER, BS>
1680    EnvironmentSpecBuilder<F, A, Missing<state::Balance>, H, T, BN, NTER, BS>
1681where
1682    F: Form,
1683    TypeSpec<F>: Default,
1684    EnvironmentSpec<F>: Default,
1685{
1686    /// Sets the `Balance` type of the environment.
1687    pub fn balance(
1688        self,
1689        balance: TypeSpec<F>,
1690    ) -> EnvironmentSpecBuilder<F, A, state::Balance, H, T, BN, NTER, BS> {
1691        EnvironmentSpecBuilder {
1692            spec: EnvironmentSpec {
1693                balance,
1694                ..self.spec
1695            },
1696            marker: PhantomData,
1697        }
1698    }
1699}
1700
1701impl<F, A, B, T, BN, NTER, BS>
1702    EnvironmentSpecBuilder<F, A, B, Missing<state::Hash>, T, BN, NTER, BS>
1703where
1704    F: Form,
1705    TypeSpec<F>: Default,
1706    EnvironmentSpec<F>: Default,
1707{
1708    /// Sets the `Hash` type of the environment.
1709    pub fn hash(
1710        self,
1711        hash: TypeSpec<F>,
1712    ) -> EnvironmentSpecBuilder<F, A, B, state::Hash, T, BN, NTER, BS> {
1713        EnvironmentSpecBuilder {
1714            spec: EnvironmentSpec { hash, ..self.spec },
1715            marker: PhantomData,
1716        }
1717    }
1718}
1719
1720impl<F, A, B, H, BN, NTER, BS>
1721    EnvironmentSpecBuilder<F, A, B, H, Missing<state::Timestamp>, BN, NTER, BS>
1722where
1723    F: Form,
1724    TypeSpec<F>: Default,
1725    EnvironmentSpec<F>: Default,
1726{
1727    /// Sets the `Timestamp` type of the environment.
1728    pub fn timestamp(
1729        self,
1730        timestamp: TypeSpec<F>,
1731    ) -> EnvironmentSpecBuilder<F, A, B, H, state::Timestamp, BN, NTER, BS> {
1732        EnvironmentSpecBuilder {
1733            spec: EnvironmentSpec {
1734                timestamp,
1735                ..self.spec
1736            },
1737            marker: PhantomData,
1738        }
1739    }
1740}
1741
1742impl<F, A, B, H, T, NTER, BS>
1743    EnvironmentSpecBuilder<F, A, B, H, T, Missing<state::BlockNumber>, NTER, BS>
1744where
1745    F: Form,
1746    TypeSpec<F>: Default,
1747    EnvironmentSpec<F>: Default,
1748{
1749    /// Sets the `BlockNumber` type of the environment.
1750    pub fn block_number(
1751        self,
1752        block_number: TypeSpec<F>,
1753    ) -> EnvironmentSpecBuilder<F, A, B, H, T, state::BlockNumber, NTER, BS> {
1754        EnvironmentSpecBuilder {
1755            spec: EnvironmentSpec {
1756                block_number,
1757                ..self.spec
1758            },
1759            marker: PhantomData,
1760        }
1761    }
1762}
1763
1764impl<F, A, B, H, T, BN, BS>
1765    EnvironmentSpecBuilder<F, A, B, H, T, BN, Missing<state::NativeToEthRatio>, BS>
1766where
1767    F: Form,
1768    TypeSpec<F>: Default,
1769    EnvironmentSpec<F>: Default,
1770{
1771    /// Sets the `NATIVE_TO_ETH_RATIO` value of the environment.
1772    pub fn native_to_eth_ratio(
1773        self,
1774        native_to_eth_ratio: u32,
1775    ) -> EnvironmentSpecBuilder<F, A, B, H, T, BN, state::NativeToEthRatio, BS> {
1776        EnvironmentSpecBuilder {
1777            spec: EnvironmentSpec {
1778                native_to_eth_ratio,
1779                ..self.spec
1780            },
1781            marker: PhantomData,
1782        }
1783    }
1784}
1785
1786impl<F, A, B, H, T, BN, NTER>
1787    EnvironmentSpecBuilder<F, A, B, H, T, BN, NTER, Missing<state::BufferSize>>
1788where
1789    F: Form,
1790    TypeSpec<F>: Default,
1791    EnvironmentSpec<F>: Default,
1792{
1793    /// Sets the size of the static buffer configured via environment variable.`
1794    pub fn static_buffer_size(
1795        self,
1796        static_buffer_size: usize,
1797    ) -> EnvironmentSpecBuilder<F, A, B, H, T, BN, NTER, state::BufferSize> {
1798        EnvironmentSpecBuilder {
1799            spec: EnvironmentSpec {
1800                static_buffer_size,
1801                ..self.spec
1802            },
1803            marker: PhantomData,
1804        }
1805    }
1806}
1807
1808impl<F>
1809    EnvironmentSpecBuilder<
1810        F,
1811        state::AccountId,
1812        state::Balance,
1813        state::Hash,
1814        state::Timestamp,
1815        state::BlockNumber,
1816        state::NativeToEthRatio,
1817        state::BufferSize,
1818    >
1819where
1820    F: Form,
1821    TypeSpec<F>: Default,
1822    EnvironmentSpec<F>: Default,
1823{
1824    /// Finished constructing the `EnvironmentSpec` object.
1825    pub fn done(self) -> EnvironmentSpec<F> {
1826        self.spec
1827    }
1828}