1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use std::marker::PhantomData;

use serde::{Deserialize, Serialize};

use crate::shared::{macros::states, types::ParaId};

/// HRMP channel configuration, with fine-grained configuration options.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct HrmpChannelConfig {
    sender: ParaId,
    recipient: ParaId,
    max_capacity: u32,
    max_message_size: u32,
}

impl HrmpChannelConfig {
    /// The sending parachain ID.
    pub fn sender(&self) -> ParaId {
        self.sender
    }

    /// The receiving parachain ID.
    pub fn recipient(&self) -> ParaId {
        self.recipient
    }

    /// The maximum capacity of messages in the channel.
    pub fn max_capacity(&self) -> u32 {
        self.max_capacity
    }

    /// The maximum size of a message in the channel.
    pub fn max_message_size(&self) -> u32 {
        self.max_message_size
    }
}

states! {
    Initial,
    WithSender,
    WithRecipient
}

/// HRMP channel configuration builder, used to build an [`HrmpChannelConfig`] declaratively with fields validation.
pub struct HrmpChannelConfigBuilder<State> {
    config: HrmpChannelConfig,
    _state: PhantomData<State>,
}

impl Default for HrmpChannelConfigBuilder<Initial> {
    fn default() -> Self {
        Self {
            config: HrmpChannelConfig {
                sender: 0,
                recipient: 0,
                max_capacity: 8,
                max_message_size: 512,
            },
            _state: PhantomData,
        }
    }
}

impl<A> HrmpChannelConfigBuilder<A> {
    fn transition<B>(&self, config: HrmpChannelConfig) -> HrmpChannelConfigBuilder<B> {
        HrmpChannelConfigBuilder {
            config,
            _state: PhantomData,
        }
    }
}

impl HrmpChannelConfigBuilder<Initial> {
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the sending parachain ID.
    pub fn with_sender(self, sender: ParaId) -> HrmpChannelConfigBuilder<WithSender> {
        self.transition(HrmpChannelConfig {
            sender,
            ..self.config
        })
    }
}

impl HrmpChannelConfigBuilder<WithSender> {
    /// Set the receiving parachain ID.
    pub fn with_recipient(self, recipient: ParaId) -> HrmpChannelConfigBuilder<WithRecipient> {
        self.transition(HrmpChannelConfig {
            recipient,
            ..self.config
        })
    }
}

impl HrmpChannelConfigBuilder<WithRecipient> {
    /// Set the max capacity of messages in the channel.
    pub fn with_max_capacity(self, max_capacity: u32) -> Self {
        self.transition(HrmpChannelConfig {
            max_capacity,
            ..self.config
        })
    }

    /// Set the maximum size of a message in the channel.
    pub fn with_max_message_size(self, max_message_size: u32) -> Self {
        self.transition(HrmpChannelConfig {
            max_message_size,
            ..self.config
        })
    }

    pub fn build(self) -> HrmpChannelConfig {
        self.config
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn hrmp_channel_config_builder_should_build_a_new_hrmp_channel_config_correctly() {
        let hrmp_channel_config = HrmpChannelConfigBuilder::new()
            .with_sender(1000)
            .with_recipient(2000)
            .with_max_capacity(50)
            .with_max_message_size(100)
            .build();

        assert_eq!(hrmp_channel_config.sender(), 1000);
        assert_eq!(hrmp_channel_config.recipient(), 2000);
        assert_eq!(hrmp_channel_config.max_capacity(), 50);
        assert_eq!(hrmp_channel_config.max_message_size(), 100);
    }
}