specs.rs 23.1 KB
Newer Older
Hero Bird's avatar
Hero Bird committed
1
2
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
//
3
4
5
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Hero Bird's avatar
Hero Bird committed
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
Hero Bird's avatar
Hero Bird committed
8
//
9
10
11
12
13
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
Hero Bird's avatar
Hero Bird committed
14

Hero Bird's avatar
Hero Bird committed
15
16
#![allow(clippy::new_ret_no_self)]

17
use crate::utils::serialize_as_byte_str;
Hero Bird's avatar
Hero Bird committed
18
19
20
21
22
23
#[cfg(not(feature = "std"))]
use alloc::{
    format,
    vec,
    vec::Vec,
};
Hero Bird's avatar
Hero Bird committed
24
use core::marker::PhantomData;
Andrew Jones's avatar
Andrew Jones committed
25
use scale_info::{
Hero Bird's avatar
Hero Bird committed
26
27
28
29
30
    form::{
        CompactForm,
        Form,
        MetaForm,
    },
31
    meta_type,
Hero Bird's avatar
Hero Bird committed
32
33
    IntoCompact,
    Registry,
34
    TypeInfo,
Hero Bird's avatar
Hero Bird committed
35
};
36
use serde::Serialize;
Hero Bird's avatar
Hero Bird committed
37
38
39
40
41

/// Describes a contract.
#[derive(Debug, PartialEq, Eq, Serialize)]
#[serde(bound = "F::TypeId: Serialize")]
pub struct ContractSpec<F: Form = MetaForm> {
Hero Bird's avatar
Hero Bird committed
42
43
    /// The set of constructors of the contract.
    constructors: Vec<ConstructorSpec<F>>,
Hero Bird's avatar
Hero Bird committed
44
45
46
47
48
49
50
51
52
53
54
55
56
    /// The external messages of the contract.
    messages: Vec<MessageSpec<F>>,
    /// The events of the contract.
    events: Vec<EventSpec<F>>,
    /// The contract documentation.
    docs: Vec<&'static str>,
}

impl IntoCompact for ContractSpec {
    type Output = ContractSpec<CompactForm>;

    fn into_compact(self, registry: &mut Registry) -> Self::Output {
        ContractSpec {
Hero Bird's avatar
Hero Bird committed
57
58
59
60
61
            constructors: self
                .constructors
                .into_iter()
                .map(|constructor| constructor.into_compact(registry))
                .collect::<Vec<_>>(),
Hero Bird's avatar
Hero Bird committed
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
            messages: self
                .messages
                .into_iter()
                .map(|msg| msg.into_compact(registry))
                .collect::<Vec<_>>(),
            events: self
                .events
                .into_iter()
                .map(|event| event.into_compact(registry))
                .collect::<Vec<_>>(),
            docs: self.docs,
        }
    }
}

/// The message builder is ready to finalize construction.
pub enum Valid {}
/// The message builder is not ready to finalize construction.
pub enum Invalid {}

Hero Bird's avatar
Hero Bird committed
82
/// A builder for contracts.
Hero Bird's avatar
Hero Bird committed
83
pub struct ContractSpecBuilder<S = Invalid> {
Hero Bird's avatar
Hero Bird committed
84
85
    /// The to-be-constructed contract specification.
    spec: ContractSpec,
Hero Bird's avatar
Hero Bird committed
86
87
88
89
90
    /// Marker for compile-time checking of valid contract specifications.
    marker: PhantomData<fn() -> S>,
}

impl ContractSpecBuilder<Invalid> {
Hero Bird's avatar
Hero Bird committed
91
92
93
94
95
96
    /// Sets the constructors of the contract specification.
    pub fn constructors<C>(self, constructors: C) -> ContractSpecBuilder<Valid>
    where
        C: IntoIterator<Item = ConstructorSpec>,
    {
        debug_assert!(self.spec.constructors.is_empty());
Hero Bird's avatar
Hero Bird committed
97
        ContractSpecBuilder {
Hero Bird's avatar
Hero Bird committed
98
99
100
101
102
            spec: ContractSpec {
                constructors: constructors.into_iter().collect::<Vec<_>>(),
                ..self.spec
            },
            marker: Default::default(),
Hero Bird's avatar
Hero Bird committed
103
104
105
106
107
108
109
110
111
112
        }
    }
}

impl<S> ContractSpecBuilder<S> {
    /// Sets the messages of the contract specification.
    pub fn messages<M>(self, messages: M) -> Self
    where
        M: IntoIterator<Item = MessageSpec>,
    {
Hero Bird's avatar
Hero Bird committed
113
        debug_assert!(self.spec.messages.is_empty());
Hero Bird's avatar
Hero Bird committed
114
        Self {
Hero Bird's avatar
Hero Bird committed
115
116
117
118
            spec: ContractSpec {
                messages: messages.into_iter().collect::<Vec<_>>(),
                ..self.spec
            },
Hero Bird's avatar
Hero Bird committed
119
120
121
122
123
124
125
126
127
            ..self
        }
    }

    /// Sets the events of the contract specification.
    pub fn events<E>(self, events: E) -> Self
    where
        E: IntoIterator<Item = EventSpec>,
    {
Hero Bird's avatar
Hero Bird committed
128
        debug_assert!(self.spec.events.is_empty());
Hero Bird's avatar
Hero Bird committed
129
        Self {
Hero Bird's avatar
Hero Bird committed
130
131
132
133
            spec: ContractSpec {
                events: events.into_iter().collect::<Vec<_>>(),
                ..self.spec
            },
Hero Bird's avatar
Hero Bird committed
134
135
136
137
138
139
140
141
142
            ..self
        }
    }

    /// Sets the documentation of the contract specification.
    pub fn docs<D>(self, docs: D) -> Self
    where
        D: IntoIterator<Item = &'static str>,
    {
Hero Bird's avatar
Hero Bird committed
143
        debug_assert!(self.spec.docs.is_empty());
Hero Bird's avatar
Hero Bird committed
144
        Self {
Hero Bird's avatar
Hero Bird committed
145
146
147
148
            spec: ContractSpec {
                docs: docs.into_iter().collect::<Vec<_>>(),
                ..self.spec
            },
Hero Bird's avatar
Hero Bird committed
149
150
151
152
153
154
155
156
            ..self
        }
    }
}

impl ContractSpecBuilder<Valid> {
    /// Finalizes construction of the contract specification.
    pub fn done(self) -> ContractSpec {
Hero Bird's avatar
Hero Bird committed
157
158
159
160
161
162
163
164
165
        assert!(
            !self.spec.constructors.is_empty(),
            "must have at least one constructor"
        );
        assert!(
            !self.spec.messages.is_empty(),
            "must have at least one message"
        );
        self.spec
Hero Bird's avatar
Hero Bird committed
166
167
168
169
170
    }
}

impl ContractSpec {
    /// Creates a new contract specification.
171
    pub fn new() -> ContractSpecBuilder {
Hero Bird's avatar
Hero Bird committed
172
        ContractSpecBuilder {
Hero Bird's avatar
Hero Bird committed
173
174
175
176
177
178
            spec: Self {
                constructors: Vec::new(),
                messages: Vec::new(),
                events: Vec::new(),
                docs: Vec::new(),
            },
Hero Bird's avatar
Hero Bird committed
179
180
181
182
183
            marker: PhantomData,
        }
    }
}

Hero Bird's avatar
Hero Bird committed
184
/// Describes a constructor of a contract.
Hero Bird's avatar
Hero Bird committed
185
186
#[derive(Debug, PartialEq, Eq, Serialize)]
#[serde(bound = "F::TypeId: Serialize")]
Hero Bird's avatar
Hero Bird committed
187
188
pub struct ConstructorSpec<F: Form = MetaForm> {
    /// The name of the message.
189
    name: &'static str,
Hero Bird's avatar
Hero Bird committed
190
    /// The selector hash of the message.
191
    #[serde(serialize_with = "serialize_as_byte_str")]
192
    selector: [u8; 4],
Hero Bird's avatar
Hero Bird committed
193
194
195
196
197
198
    /// The parameters of the deploy handler.
    args: Vec<MessageParamSpec<F>>,
    /// The deploy handler documentation.
    docs: Vec<&'static str>,
}

Hero Bird's avatar
Hero Bird committed
199
200
impl IntoCompact for ConstructorSpec {
    type Output = ConstructorSpec<CompactForm>;
Hero Bird's avatar
Hero Bird committed
201
202

    fn into_compact(self, registry: &mut Registry) -> Self::Output {
Hero Bird's avatar
Hero Bird committed
203
        ConstructorSpec {
204
            name: self.name,
Hero Bird's avatar
Hero Bird committed
205
            selector: self.selector,
Hero Bird's avatar
Hero Bird committed
206
207
208
209
210
211
212
213
214
215
            args: self
                .args
                .into_iter()
                .map(|arg| arg.into_compact(registry))
                .collect::<Vec<_>>(),
            docs: self.docs,
        }
    }
}

Hero Bird's avatar
Hero Bird committed
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/// A builder for constructors.
///
/// # Dev
///
/// Some of the fields are guarded by a type-state pattern to
/// fail at compile-time instead of at run-time. This is useful
/// to better debug code-gen macros.
pub struct ConstructorSpecBuilder<Selector> {
    spec: ConstructorSpec,
    marker: PhantomData<fn() -> Selector>,
}

impl ConstructorSpec {
    /// Creates a new constructor spec builder.
230
    pub fn new(name: &'static str) -> ConstructorSpecBuilder<Missing<state::Selector>> {
Hero Bird's avatar
Hero Bird committed
231
        ConstructorSpecBuilder {
Hero Bird's avatar
Hero Bird committed
232
            spec: Self {
Hero Bird's avatar
Hero Bird committed
233
                name,
234
                selector: [0u8; 4],
Hero Bird's avatar
Hero Bird committed
235
236
                args: Vec::new(),
                docs: Vec::new(),
Hero Bird's avatar
Hero Bird committed
237
            },
Hero Bird's avatar
Hero Bird committed
238
            marker: PhantomData,
Hero Bird's avatar
Hero Bird committed
239
240
241
242
        }
    }
}

Hero Bird's avatar
Hero Bird committed
243
244
impl ConstructorSpecBuilder<Missing<state::Selector>> {
    /// Sets the function selector of the message.
245
    pub fn selector(self, selector: [u8; 4]) -> ConstructorSpecBuilder<state::Selector> {
Hero Bird's avatar
Hero Bird committed
246
247
248
249
250
251
252
253
        ConstructorSpecBuilder {
            spec: ConstructorSpec {
                selector,
                ..self.spec
            },
            marker: PhantomData,
        }
    }
Hero Bird's avatar
Hero Bird committed
254
255
}

Hero Bird's avatar
Hero Bird committed
256
257
258
impl<S> ConstructorSpecBuilder<S> {
    /// Sets the input arguments of the message specification.
    pub fn args<A>(self, args: A) -> Self
Hero Bird's avatar
Hero Bird committed
259
260
261
262
263
264
265
266
267
    where
        A: IntoIterator<Item = MessageParamSpec>,
    {
        let mut this = self;
        debug_assert!(this.spec.args.is_empty());
        this.spec.args = args.into_iter().collect::<Vec<_>>();
        this
    }

Hero Bird's avatar
Hero Bird committed
268
269
    /// Sets the documentation of the message specification.
    pub fn docs<D>(self, docs: D) -> Self
Hero Bird's avatar
Hero Bird committed
270
271
272
273
274
275
276
277
    where
        D: IntoIterator<Item = &'static str>,
    {
        let mut this = self;
        debug_assert!(this.spec.docs.is_empty());
        this.spec.docs = docs.into_iter().collect::<Vec<_>>();
        this
    }
Hero Bird's avatar
Hero Bird committed
278
}
Hero Bird's avatar
Hero Bird committed
279

Hero Bird's avatar
Hero Bird committed
280
281
282
impl ConstructorSpecBuilder<state::Selector> {
    /// Finishes construction of the constructor.
    pub fn done(self) -> ConstructorSpec {
Hero Bird's avatar
Hero Bird committed
283
284
285
286
287
288
289
        self.spec
    }
}

/// Describes a contract message.
#[derive(Debug, PartialEq, Eq, Serialize)]
#[serde(bound = "F::TypeId: Serialize")]
Andrew Jones's avatar
Andrew Jones committed
290
#[serde(rename_all = "camelCase")]
Hero Bird's avatar
Hero Bird committed
291
292
pub struct MessageSpec<F: Form = MetaForm> {
    /// The name of the message.
293
    name: &'static str,
Hero Bird's avatar
Hero Bird committed
294
    /// The selector hash of the message.
295
    #[serde(serialize_with = "serialize_as_byte_str")]
296
    selector: [u8; 4],
Hero Bird's avatar
Hero Bird committed
297
298
299
300
301
302
303
304
305
306
    /// If the message is allowed to mutate the contract state.
    mutates: bool,
    /// The parameters of the message.
    args: Vec<MessageParamSpec<F>>,
    /// The return type of the message.
    return_type: ReturnTypeSpec<F>,
    /// The message documentation.
    docs: Vec<&'static str>,
}

Hero Bird's avatar
Hero Bird committed
307
308
309
310
/// Type state for builders to tell that some mandatory state has not yet been set
/// yet or to fail upon setting the same state multiple times.
pub struct Missing<S>(PhantomData<fn() -> S>);

Hero Bird's avatar
Hero Bird committed
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
mod state {
    //! Type states that tell what state of a message has not
    //! yet been set properly for a valid construction.

    /// Type state for the message selector of a message.
    pub struct Selector;
    /// Type state for the mutability of a message.
    pub struct Mutates;
    /// Type state for the return type of a message.
    pub struct Returns;
}

impl MessageSpec {
    /// Creates a new message spec builder.
    pub fn new(
326
        name: &'static str,
Hero Bird's avatar
Hero Bird committed
327
328
329
330
331
332
333
334
    ) -> MessageSpecBuilder<
        Missing<state::Selector>,
        Missing<state::Mutates>,
        Missing<state::Returns>,
    > {
        MessageSpecBuilder {
            spec: Self {
                name,
335
                selector: [0u8; 4],
Hero Bird's avatar
Hero Bird committed
336
                mutates: false,
Hero Bird's avatar
Hero Bird committed
337
338
339
                args: Vec::new(),
                return_type: ReturnTypeSpec::new(None),
                docs: Vec::new(),
Hero Bird's avatar
Hero Bird committed
340
341
342
343
344
345
346
347
348
349
350
351
352
            },
            marker: PhantomData,
        }
    }
}

/// A builder for messages.
///
/// # Dev
///
/// Some of the fields are guarded by a type-state pattern to
/// fail at compile-time instead of at run-time. This is useful
/// to better debug code-gen macros.
Qinxuan Chen's avatar
Qinxuan Chen committed
353
#[allow(clippy::type_complexity)]
Hero Bird's avatar
Hero Bird committed
354
355
356
357
358
359
360
pub struct MessageSpecBuilder<Selector, Mutates, Returns> {
    spec: MessageSpec,
    marker: PhantomData<fn() -> (Selector, Mutates, Returns)>,
}

impl<M, R> MessageSpecBuilder<Missing<state::Selector>, M, R> {
    /// Sets the function selector of the message.
361
362
363
364
    pub fn selector(
        self,
        selector: [u8; 4],
    ) -> MessageSpecBuilder<state::Selector, M, R> {
Hero Bird's avatar
Hero Bird committed
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
        MessageSpecBuilder {
            spec: MessageSpec {
                selector,
                ..self.spec
            },
            marker: PhantomData,
        }
    }
}

impl<S, R> MessageSpecBuilder<S, Missing<state::Mutates>, R> {
    /// Sets if the message is mutable, thus taking `&mut self` or not thus taking `&self`.
    pub fn mutates(self, mutates: bool) -> MessageSpecBuilder<S, state::Mutates, R> {
        MessageSpecBuilder {
            spec: MessageSpec {
                mutates,
                ..self.spec
            },
            marker: PhantomData,
        }
    }
}

impl<M, S> MessageSpecBuilder<S, M, Missing<state::Returns>> {
    /// Sets the return type of the message.
    pub fn returns(
        self,
        return_type: ReturnTypeSpec,
    ) -> MessageSpecBuilder<S, M, state::Returns> {
        MessageSpecBuilder {
            spec: MessageSpec {
                return_type,
                ..self.spec
            },
            marker: PhantomData,
        }
    }
}

impl<S, M, R> MessageSpecBuilder<S, M, R> {
    /// Sets the input arguments of the message specification.
    pub fn args<A>(self, args: A) -> Self
    where
        A: IntoIterator<Item = MessageParamSpec>,
    {
        let mut this = self;
        debug_assert!(this.spec.args.is_empty());
        this.spec.args = args.into_iter().collect::<Vec<_>>();
        this
    }

    /// Sets the documentation of the message specification.
    pub fn docs<D>(self, docs: D) -> Self
    where
        D: IntoIterator<Item = &'static str>,
    {
        let mut this = self;
        debug_assert!(this.spec.docs.is_empty());
        this.spec.docs = docs.into_iter().collect::<Vec<_>>();
        this
    }
}

impl MessageSpecBuilder<state::Selector, state::Mutates, state::Returns> {
    /// Finishes construction of the message.
    pub fn done(self) -> MessageSpec {
        self.spec
    }
}

impl IntoCompact for MessageSpec {
    type Output = MessageSpec<CompactForm>;

    fn into_compact(self, registry: &mut Registry) -> Self::Output {
        MessageSpec {
440
            name: self.name,
Hero Bird's avatar
Hero Bird committed
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
            selector: self.selector,
            mutates: self.mutates,
            args: self
                .args
                .into_iter()
                .map(|arg| arg.into_compact(registry))
                .collect::<Vec<_>>(),
            return_type: self.return_type.into_compact(registry),
            docs: self.docs,
        }
    }
}

/// Describes an event definition.
#[derive(Debug, PartialEq, Eq, Serialize)]
#[serde(bound = "F::TypeId: Serialize")]
pub struct EventSpec<F: Form = MetaForm> {
    /// The name of the event.
459
    name: &'static str,
Hero Bird's avatar
Hero Bird committed
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
    /// The event arguments.
    args: Vec<EventParamSpec<F>>,
    /// The event documentation.
    docs: Vec<&'static str>,
}

/// An event specification builder.
pub struct EventSpecBuilder {
    spec: EventSpec,
}

impl EventSpecBuilder {
    /// Sets the input arguments of the event specification.
    pub fn args<A>(self, args: A) -> Self
    where
        A: IntoIterator<Item = EventParamSpec>,
    {
        let mut this = self;
        debug_assert!(this.spec.args.is_empty());
        this.spec.args = args.into_iter().collect::<Vec<_>>();
        this
    }

    /// Sets the input arguments of the event specification.
    pub fn docs<D>(self, docs: D) -> Self
    where
        D: IntoIterator<Item = &'static str>,
    {
        let mut this = self;
        debug_assert!(this.spec.docs.is_empty());
        this.spec.docs = docs.into_iter().collect::<Vec<_>>();
        this
    }

    /// Finalizes building the event specification.
    pub fn done(self) -> EventSpec {
        self.spec
    }
}

impl IntoCompact for EventSpec {
    type Output = EventSpec<CompactForm>;

    fn into_compact(self, registry: &mut Registry) -> Self::Output {
        EventSpec {
505
            name: self.name,
Hero Bird's avatar
Hero Bird committed
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
            args: self
                .args
                .into_iter()
                .map(|arg| arg.into_compact(registry))
                .collect::<Vec<_>>(),
            docs: self.docs,
        }
    }
}

impl EventSpec {
    /// Creates a new event specification builder.
    pub fn new(name: &'static str) -> EventSpecBuilder {
        EventSpecBuilder {
            spec: Self {
                name,
Hero Bird's avatar
Hero Bird committed
522
523
                args: Vec::new(),
                docs: Vec::new(),
Hero Bird's avatar
Hero Bird committed
524
525
526
527
528
            },
        }
    }
}

Hero Bird's avatar
Hero Bird committed
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
/// Describes the syntactical name of a type at a given type position.
///
/// This is important when trying to work with type aliases.
/// Normally a type alias is transparent and so scenarios such as
/// ```no_compile
/// type Foo = i32;
/// fn bar(foo: Foo);
/// ```
/// Will only communicate that `foo` is of type `i32` which is correct,
/// however, it will miss the potentially important information that it
/// is being used through a type alias named `Foo`.
///
/// In ink! we current experience this problem with environmental types
/// such as the `Balance` type that is just a type alias to `u128` in the
/// default setup. Even though it would be useful for third party tools
/// such as the Polkadot UI to know that we are handling with `Balance`
/// types, we currently cannot communicate this without display names.
546
pub type DisplayName = scale_info::Path;
Hero Bird's avatar
Hero Bird committed
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566

/// A type specification.
///
/// This contains the actual type as well as an optional compile-time
/// known displayed representation of the type. This is useful for cases
/// where the type is used through a type alias in order to provide
/// information about the alias name.
///
/// # Examples
///
/// Consider the following Rust function:
/// ```no_compile
/// fn is_sorted(input: &[i32], pred: Predicate) -> bool;
/// ```
/// In this above example `input` would have no displayable name,
/// `pred`'s display name is `Predicate` and the display name of
/// the return type is simply `bool`. Note that `Predicate` could
/// simply be a type alias to `fn(i32, i32) -> Ordering`.
#[derive(Debug, PartialEq, Eq, Serialize)]
#[serde(bound = "F::TypeId: Serialize")]
Andrew Jones's avatar
Andrew Jones committed
567
#[serde(rename_all = "camelCase")]
Hero Bird's avatar
Hero Bird committed
568
569
pub struct TypeSpec<F: Form = MetaForm> {
    /// The actual type.
Andrew Jones's avatar
Andrew Jones committed
570
    id: F::TypeId,
Hero Bird's avatar
Hero Bird committed
571
    /// The compile-time known displayed representation of the type.
572
    display_name: DisplayName,
Hero Bird's avatar
Hero Bird committed
573
574
575
576
577
578
579
}

impl IntoCompact for TypeSpec {
    type Output = TypeSpec<CompactForm>;

    fn into_compact(self, registry: &mut Registry) -> Self::Output {
        TypeSpec {
Andrew Jones's avatar
Andrew Jones committed
580
            id: registry.register_type(&self.id),
581
            display_name: self.display_name,
Hero Bird's avatar
Hero Bird committed
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
        }
    }
}

impl TypeSpec {
    /// Creates a new type specification with a display name.
    ///
    /// The name is any valid Rust identifier or path.
    ///
    /// # Examples
    ///
    /// Valid display names are `foo`, `foo::bar`, `foo::bar::Baz`, etc.
    ///
    /// # Panics
    ///
    /// Panics if the given display name is invalid.
    pub fn with_name_str<T>(display_name: &'static str) -> Self
    where
600
        T: TypeInfo + 'static,
Hero Bird's avatar
Hero Bird committed
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
    {
        Self::with_name_segs::<T, _>(display_name.split("::"))
    }

    /// Creates a new type specification with a display name
    /// represented by the given path segments.
    ///
    /// The display name segments all must be valid Rust identifiers.
    ///
    /// # Examples
    ///
    /// Valid display names are `foo`, `foo::bar`, `foo::bar::Baz`, etc.
    ///
    /// # Panics
    ///
    /// Panics if the given display name is invalid.
    pub fn with_name_segs<T, S>(segments: S) -> Self
    where
619
        T: TypeInfo + 'static,
620
        S: IntoIterator<Item = &'static str>,
Hero Bird's avatar
Hero Bird committed
621
622
    {
        Self {
623
            id: meta_type::<T>(),
Andrew Jones's avatar
Andrew Jones committed
624
625
            display_name: DisplayName::from_segments(segments)
                .expect("display name is invalid"),
Hero Bird's avatar
Hero Bird committed
626
627
628
629
630
631
        }
    }

    /// Creates a new type specification without a display name.
    pub fn new<T>() -> Self
    where
632
        T: TypeInfo + 'static,
Hero Bird's avatar
Hero Bird committed
633
634
    {
        Self {
635
            id: meta_type::<T>(),
Andrew Jones's avatar
Andrew Jones committed
636
            display_name: DisplayName::default(),
Hero Bird's avatar
Hero Bird committed
637
638
639
640
        }
    }
}

Hero Bird's avatar
Hero Bird committed
641
642
643
644
645
/// Describes a pair of parameter name and type.
#[derive(Debug, PartialEq, Eq, Serialize)]
#[serde(bound = "F::TypeId: Serialize")]
pub struct EventParamSpec<F: Form = MetaForm> {
    /// The name of the parameter.
646
    name: &'static str,
Hero Bird's avatar
Hero Bird committed
647
648
649
650
    /// If the event parameter is indexed.
    indexed: bool,
    /// The type of the parameter.
    #[serde(rename = "type")]
Hero Bird's avatar
Hero Bird committed
651
    ty: TypeSpec<F>,
652
653
    /// The documentation associated with the arguments.
    docs: Vec<&'static str>,
Hero Bird's avatar
Hero Bird committed
654
655
656
657
658
659
660
}

impl IntoCompact for EventParamSpec {
    type Output = EventParamSpec<CompactForm>;

    fn into_compact(self, registry: &mut Registry) -> Self::Output {
        EventParamSpec {
661
            name: self.name,
Hero Bird's avatar
Hero Bird committed
662
            indexed: self.indexed,
Hero Bird's avatar
Hero Bird committed
663
            ty: self.ty.into_compact(registry),
664
            docs: self.docs,
Hero Bird's avatar
Hero Bird committed
665
666
667
668
669
        }
    }
}

impl EventParamSpec {
Hero Bird's avatar
Hero Bird committed
670
671
672
673
674
675
676
677
678
    /// Creates a new event parameter specification builder.
    pub fn new(name: &'static str) -> EventParamSpecBuilder {
        EventParamSpecBuilder {
            spec: Self {
                name,
                // By default event parameters are not indexed.
                indexed: false,
                // We initialize every parameter type as `()`.
                ty: TypeSpec::new::<()>(),
679
680
                // We start with empty docs.
                docs: vec![],
Hero Bird's avatar
Hero Bird committed
681
            },
Hero Bird's avatar
Hero Bird committed
682
683
        }
    }
Hero Bird's avatar
Hero Bird committed
684
}
Hero Bird's avatar
Hero Bird committed
685

Hero Bird's avatar
Hero Bird committed
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
/// Used to construct an event parameter specification.
pub struct EventParamSpecBuilder {
    /// The built-up event parameter specification.
    spec: EventParamSpec,
}

impl EventParamSpecBuilder {
    /// Sets the type of the event parameter.
    pub fn of_type(self, spec: TypeSpec) -> Self {
        let mut this = self;
        this.spec.ty = spec;
        this
    }

    /// If the event parameter is indexed.
    pub fn indexed(self, is_indexed: bool) -> Self {
        let mut this = self;
        this.spec.indexed = is_indexed;
        this
    }

707
708
709
710
711
712
713
714
715
716
717
718
719
720
    /// Sets the documentation of the event parameter.
    pub fn docs<D>(self, docs: D) -> Self
    where
        D: IntoIterator<Item = &'static str>,
    {
        debug_assert!(self.spec.docs.is_empty());
        Self {
            spec: EventParamSpec {
                docs: docs.into_iter().collect::<Vec<_>>(),
                ..self.spec
            },
        }
    }

Hero Bird's avatar
Hero Bird committed
721
722
723
    /// Finishes constructing the event parameter spec.
    pub fn done(self) -> EventParamSpec {
        self.spec
Hero Bird's avatar
Hero Bird committed
724
725
726
727
728
729
730
731
732
    }
}

/// Describes the return type of a contract message.
#[derive(Debug, PartialEq, Eq, Serialize)]
#[serde(transparent)]
#[serde(bound = "F::TypeId: Serialize")]
pub struct ReturnTypeSpec<F: Form = MetaForm> {
    #[serde(rename = "type")]
Hero Bird's avatar
Hero Bird committed
733
    opt_type: Option<TypeSpec<F>>,
Hero Bird's avatar
Hero Bird committed
734
735
736
737
738
739
740
}

impl IntoCompact for ReturnTypeSpec {
    type Output = ReturnTypeSpec<CompactForm>;

    fn into_compact(self, registry: &mut Registry) -> Self::Output {
        ReturnTypeSpec {
Hero Bird's avatar
Hero Bird committed
741
742
743
            opt_type: self
                .opt_type
                .map(|opt_type| opt_type.into_compact(registry)),
Hero Bird's avatar
Hero Bird committed
744
745
746
747
748
        }
    }
}

impl ReturnTypeSpec {
Hero Bird's avatar
Hero Bird committed
749
750
751
752
753
    /// Creates a new return type specification from the given type or `None`.
    ///
    /// # Examples
    ///
    /// ```no_run
754
    /// # use ink_metadata::{TypeSpec, ReturnTypeSpec};
Hero Bird's avatar
Hero Bird committed
755
756
757
758
    /// ReturnTypeSpec::new(None); // no return type;
    /// ReturnTypeSpec::new(TypeSpec::new::<i32>()); // return type of `i32`
    /// ```
    pub fn new<T>(ty: T) -> Self
Hero Bird's avatar
Hero Bird committed
759
    where
Hero Bird's avatar
Hero Bird committed
760
        T: Into<Option<TypeSpec>>,
Hero Bird's avatar
Hero Bird committed
761
762
    {
        Self {
Hero Bird's avatar
Hero Bird committed
763
            opt_type: ty.into(),
Hero Bird's avatar
Hero Bird committed
764
765
766
767
768
769
770
771
772
        }
    }
}

/// Describes a pair of parameter name and type.
#[derive(Debug, PartialEq, Eq, Serialize)]
#[serde(bound = "F::TypeId: Serialize")]
pub struct MessageParamSpec<F: Form = MetaForm> {
    /// The name of the parameter.
773
    name: &'static str,
Hero Bird's avatar
Hero Bird committed
774
775
    /// The type of the parameter.
    #[serde(rename = "type")]
Hero Bird's avatar
Hero Bird committed
776
    ty: TypeSpec<F>,
Hero Bird's avatar
Hero Bird committed
777
778
779
780
781
782
783
}

impl IntoCompact for MessageParamSpec {
    type Output = MessageParamSpec<CompactForm>;

    fn into_compact(self, registry: &mut Registry) -> Self::Output {
        MessageParamSpec {
784
            name: self.name,
Hero Bird's avatar
Hero Bird committed
785
            ty: self.ty.into_compact(registry),
Hero Bird's avatar
Hero Bird committed
786
787
788
789
790
        }
    }
}

impl MessageParamSpec {
Hero Bird's avatar
Hero Bird committed
791
792
793
794
795
796
797
798
    /// Constructs a new message parameter specification via builder.
    pub fn new(name: &'static str) -> MessageParamSpecBuilder {
        MessageParamSpecBuilder {
            spec: Self {
                name,
                // Uses `()` type by default.
                ty: TypeSpec::new::<()>(),
            },
Hero Bird's avatar
Hero Bird committed
799
800
        }
    }
Hero Bird's avatar
Hero Bird committed
801
}
Hero Bird's avatar
Hero Bird committed
802

Hero Bird's avatar
Hero Bird committed
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
/// Used to construct a message parameter specification.
pub struct MessageParamSpecBuilder {
    /// The to-be-constructed message parameter specification.
    spec: MessageParamSpec,
}

impl MessageParamSpecBuilder {
    /// Sets the type of the message parameter.
    pub fn of_type(self, ty: TypeSpec) -> Self {
        let mut this = self;
        this.spec.ty = ty;
        this
    }

    /// Finishes construction of the message parameter.
    pub fn done(self) -> MessageParamSpec {
        self.spec
Hero Bird's avatar
Hero Bird committed
820
821
    }
}