Skip to main content

tlb_ton/
state_init.rs

1//! Collection of types related to [StateInit](https://docs.ton.org/develop/data-formats/msg-tlb#stateinit-tl-b)
2use impl_tools::autoimpl;
3use tlb::{
4    Cell, ParseFully, Ref, Same,
5    bits::{
6        NBits, NoArgs,
7        de::{BitReader, BitReaderExt, BitUnpack},
8        ser::{BitPack, BitWriter, BitWriterExt},
9    },
10    de::{CellDeserialize, CellParser, CellParserError},
11    hashmap::HashmapE,
12    ser::{CellBuilder, CellBuilderError, CellSerialize, CellSerializeExt},
13};
14
15/// [StateInit](https://docs.ton.org/develop/data-formats/msg-tlb#stateinit-tl-b)
16/// ```tlb
17/// _ split_depth:(Maybe (## 5)) special:(Maybe TickTock)
18/// code:(Maybe ^Cell) data:(Maybe ^Cell)
19/// library:(HashmapE 256 SimpleLib) = StateInitWithLibs;
20/// ```
21#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
22#[derive(Debug, Clone, PartialEq, Eq)]
23#[autoimpl(Default)]
24pub struct StateInit<C = Cell, D = Cell> {
25    pub split_depth: Option<u8>,
26    pub special: Option<TickTock>,
27    pub code: Option<C>,
28    pub data: Option<D>,
29    #[cfg_attr(feature = "arbitrary", arbitrary(default))] // TODO
30    pub library: HashmapE<SimpleLib>,
31}
32
33impl<IC, ID> StateInit<IC, ID>
34where
35    IC: CellSerialize<Args: NoArgs>,
36    ID: CellSerialize<Args: NoArgs>,
37{
38    #[inline]
39    pub fn normalize(&self) -> Result<StateInit, CellBuilderError> {
40        Ok(StateInit {
41            split_depth: self.split_depth,
42            special: self.special,
43            code: self
44                .code
45                .as_ref()
46                .map(|c| c.to_cell(NoArgs::EMPTY))
47                .transpose()?,
48            data: self
49                .data
50                .as_ref()
51                .map(|d| d.to_cell(NoArgs::EMPTY))
52                .transpose()?,
53            library: self.library.clone(),
54        })
55    }
56}
57
58impl<C, D> CellSerialize for StateInit<C, D>
59where
60    C: CellSerialize<Args: NoArgs>,
61    D: CellSerialize<Args: NoArgs>,
62{
63    type Args = ();
64
65    #[inline]
66    fn store(&self, builder: &mut CellBuilder, (): Self::Args) -> Result<(), CellBuilderError> {
67        builder
68            // split_depth:(Maybe (## 5))
69            .pack_as::<_, Option<NBits<5>>>(self.split_depth, ())?
70            // special:(Maybe TickTock)
71            .pack(self.special, ())?
72            // code:(Maybe ^Cell)
73            .store_as::<_, Option<Ref>>(self.code.as_ref(), NoArgs::EMPTY)?
74            // data:(Maybe ^Cell)
75            .store_as::<_, Option<Ref>>(self.data.as_ref(), NoArgs::EMPTY)?
76            // library:(HashmapE 256 SimpleLib)
77            .store_as::<_, &HashmapE<Same, Same>>(&self.library, (256, (), ()))?;
78        Ok(())
79    }
80}
81
82impl<'de, C, D> CellDeserialize<'de> for StateInit<C, D>
83where
84    C: CellDeserialize<'de, Args: NoArgs>,
85    D: CellDeserialize<'de, Args: NoArgs>,
86{
87    type Args = ();
88
89    #[inline]
90    fn parse(parser: &mut CellParser<'de>, (): Self::Args) -> Result<Self, CellParserError<'de>> {
91        Ok(Self {
92            // split_depth:(Maybe (## 5))
93            split_depth: parser.unpack_as::<_, Option<NBits<5>>>(())?,
94            // special:(Maybe TickTock)
95            special: parser.unpack(())?,
96            // code:(Maybe ^Cell)
97            code: parser.parse_as::<_, Option<Ref<ParseFully>>>(NoArgs::EMPTY)?,
98            // data:(Maybe ^Cell)
99            data: parser.parse_as::<_, Option<Ref<ParseFully>>>(NoArgs::EMPTY)?,
100            // library:(HashmapE 256 SimpleLib)
101            library: parser.parse_as::<_, HashmapE<Same, Same>>((256, (), ()))?,
102        })
103    }
104}
105
106/// `tick_tock` field for [`StateInit`]
107/// ```tlb
108/// tick_tock$_ tick:Bool tock:Bool = TickTock;
109/// ```
110#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
111#[derive(Debug, Clone, Copy, PartialEq, Eq)]
112pub struct TickTock {
113    pub tick: bool,
114    pub tock: bool,
115}
116
117impl BitPack for TickTock {
118    type Args = ();
119
120    #[inline]
121    fn pack<W>(&self, writer: &mut W, (): Self::Args) -> Result<(), W::Error>
122    where
123        W: BitWriter + ?Sized,
124    {
125        writer.pack(self.tick, ())?.pack(self.tock, ())?;
126        Ok(())
127    }
128}
129
130impl<'de> BitUnpack<'de> for TickTock {
131    type Args = ();
132
133    #[inline]
134    fn unpack<R>(reader: &mut R, (): Self::Args) -> Result<Self, R::Error>
135    where
136        R: BitReader<'de> + ?Sized,
137    {
138        Ok(Self {
139            tick: reader.unpack(())?,
140            tock: reader.unpack(())?,
141        })
142    }
143}
144
145/// `library` field for [`StateInit`]
146/// ```tlb
147/// simple_lib$_ public:Bool root:^Cell = SimpleLib;
148/// ```
149#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
150#[derive(Debug, Clone, PartialEq, Eq)]
151pub struct SimpleLib {
152    pub public: bool,
153    pub root: Cell,
154}
155
156impl CellSerialize for SimpleLib {
157    type Args = ();
158
159    #[inline]
160    fn store(&self, builder: &mut CellBuilder, (): Self::Args) -> Result<(), CellBuilderError> {
161        builder
162            .pack(self.public, ())?
163            .store_as::<_, Ref>(&self.root, ())?;
164        Ok(())
165    }
166}
167
168impl<'de> CellDeserialize<'de> for SimpleLib {
169    type Args = ();
170
171    #[inline]
172    fn parse(parser: &mut CellParser<'de>, (): Self::Args) -> Result<Self, CellParserError<'de>> {
173        Ok(Self {
174            public: parser.unpack(())?,
175            root: parser.parse_as::<_, Ref>(())?,
176        })
177    }
178}
179
180#[cfg(test)]
181mod tests {
182    use tlb::ser::CellSerializeExt;
183
184    use super::*;
185
186    #[test]
187    fn state_init_serde() {
188        let s = StateInit::<(), ()>::default();
189        let cell = s.to_cell(()).unwrap();
190        let got: StateInit<(), ()> = cell.parse_fully(()).unwrap();
191        assert_eq!(got, s);
192    }
193}