1use std::borrow::Borrow;
4
5use crate::cell::*;
6use crate::error::Error;
7use crate::num::*;
8
9use crate::models::account::StateInit;
10use crate::models::currency::CurrencyCollection;
11
12pub use self::address::*;
13pub use self::envelope::*;
14pub use self::in_message::*;
15pub use self::out_message::*;
16
17mod address;
18mod envelope;
19mod in_message;
20mod out_message;
21#[cfg(test)]
22mod tests;
23
24pub type Message<'a> = BaseMessage<MsgInfo, CellSlice<'a>>;
26
27impl EquivalentRepr<OwnedMessage> for Message<'_> {}
28impl EquivalentRepr<RelaxedMessage<'_>> for Message<'_> {}
29impl EquivalentRepr<OwnedRelaxedMessage> for Message<'_> {}
30
31pub type OwnedMessage = BaseMessage<MsgInfo, CellSliceParts>;
33
34impl EquivalentRepr<Message<'_>> for OwnedMessage {}
35impl EquivalentRepr<RelaxedMessage<'_>> for OwnedMessage {}
36impl EquivalentRepr<OwnedRelaxedMessage> for OwnedMessage {}
37
38pub type RelaxedMessage<'a> = BaseMessage<RelaxedMsgInfo, CellSlice<'a>>;
40
41impl EquivalentRepr<Message<'_>> for RelaxedMessage<'_> {}
42impl EquivalentRepr<OwnedMessage> for RelaxedMessage<'_> {}
43impl EquivalentRepr<OwnedRelaxedMessage> for RelaxedMessage<'_> {}
44
45pub type OwnedRelaxedMessage = BaseMessage<RelaxedMsgInfo, CellSliceParts>;
47
48impl EquivalentRepr<Message<'_>> for OwnedRelaxedMessage {}
49impl EquivalentRepr<OwnedMessage> for OwnedRelaxedMessage {}
50impl EquivalentRepr<RelaxedMessage<'_>> for OwnedRelaxedMessage {}
51
52#[derive(Debug, Clone)]
54pub struct BaseMessage<I, B> {
55 pub info: I,
57 pub init: Option<StateInit>,
59 pub body: B,
61 pub layout: Option<MessageLayout>,
63}
64
65#[cfg(feature = "serde")]
66impl<I, B> serde::Serialize for BaseMessage<I, B>
67where
68 I: ExactSize + Store + serde::Serialize,
69 B: ExactSize + StoreBody,
70{
71 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
72 use serde::ser::{Error, SerializeStruct};
73
74 struct BodySerializer<'a, B: StoreBody>(&'a B);
75
76 impl<B: StoreBody> serde::Serialize for BodySerializer<'_, B> {
77 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
78 let mut builder = CellBuilder::new();
79 ok!(self
80 .0
81 .store_body(false, &mut builder, &mut Cell::empty_context())
82 .map_err(Error::custom));
83 let cell = ok!(builder.build().map_err(Error::custom));
84 crate::boc::Boc::serialize(&cell, serializer)
85 }
86 }
87
88 if serializer.is_human_readable() {
89 let mut ser = ok!(serializer.serialize_struct("Message", 4));
90 ok!(ser.serialize_field("info", &self.info));
91 ok!(ser.serialize_field("init", &self.init));
92 ok!(ser.serialize_field("body", &BodySerializer(&self.body)));
93 ok!(ser.serialize_field("layout", &self.layout));
94 ser.end()
95 } else {
96 crate::boc::BocRepr::serialize(self, serializer)
97 }
98 }
99}
100
101#[cfg(feature = "serde")]
102impl<'de, I> serde::Deserialize<'de> for BaseMessage<I, CellSliceParts>
103where
104 for<'a> I: ExactSize + Load<'a> + serde::Deserialize<'de>,
105{
106 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
107 where
108 D: serde::Deserializer<'de>,
109 {
110 #[derive(serde::Deserialize)]
111 struct Message<I> {
112 info: I,
113 #[serde(default)]
114 init: Option<StateInit>,
115 #[serde(with = "crate::boc::Boc", default)]
116 body: Cell,
117 #[serde(default)]
118 layout: Option<MessageLayout>,
119 }
120
121 if deserializer.is_human_readable() {
122 let msg = Message::deserialize(deserializer)?;
123 let body_range = CellSliceRange::full(msg.body.as_ref());
124 Ok(Self {
125 info: msg.info,
126 init: msg.init,
127 body: (msg.body, body_range),
128 layout: msg.layout,
129 })
130 } else {
131 crate::boc::BocRepr::deserialize(deserializer)
132 }
133 }
134}
135
136impl<I: Borrow<MsgInfo>, B> BaseMessage<I, B> {
137 pub fn ty(&self) -> MsgType {
139 self.info.borrow().ty()
140 }
141}
142
143impl<I: ExactSize, B: ExactSize> BaseMessage<I, B> {
144 pub fn compute_layout(info: &I, init: Option<&StateInit>, body: &B) -> MessageLayout {
146 let (layout, ..) = MessageLayout::compute(info.exact_size(), init, body.exact_size());
147 layout
148 }
149}
150
151impl<I, B> Store for BaseMessage<I, B>
152where
153 I: Store + ExactSize,
154 B: StoreBody + ExactSize,
155{
156 fn store_into(
157 &self,
158 builder: &mut CellBuilder,
159 context: &mut dyn CellContext,
160 ) -> Result<(), Error> {
161 let info_size = self.info.exact_size();
162 let body_size = self.body.exact_size();
163 let (layout, size) = match self.layout {
164 Some(layout) => {
165 let size = layout.compute_full_size(info_size, self.init.as_ref(), body_size);
166 (layout, size)
167 }
168 None => MessageLayout::compute(info_size, self.init.as_ref(), body_size),
169 };
170 let Size { bits, refs } = size;
171
172 if !builder.has_capacity(bits, refs) {
174 return Err(Error::CellOverflow);
175 }
176
177 ok!(self.info.store_into(builder, context));
179
180 ok!(match &self.init {
182 Some(value) => {
183 ok!(builder.store_bit_one()); SliceOrCell {
185 to_cell: layout.init_to_cell,
186 value,
187 }
188 .store_into(builder, context)
189 }
190 None => builder.store_bit_zero(), });
192
193 ok!(builder.store_bit(layout.body_to_cell));
195 self.body.store_body(layout.body_to_cell, builder, context)
196 }
197}
198
199impl<'a, I, B> Load<'a> for BaseMessage<I, B>
200where
201 I: Load<'a>,
202 B: LoadBody<'a>,
203{
204 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
205 let info = ok!(I::load_from(slice));
206 let init = ok!(Option::<SliceOrCell<StateInit>>::load_from(slice));
207
208 let body_to_cell = ok!(slice.load_bit());
209 let body = ok!(B::load_body(body_to_cell, slice));
210
211 let (init, init_to_cell) = match init {
212 Some(SliceOrCell { to_cell, value }) => (Some(value), to_cell),
213 None => (None, false),
214 };
215
216 let layout = MessageLayout {
217 init_to_cell,
218 body_to_cell,
219 };
220
221 Ok(Self {
222 info,
223 init,
224 body,
225 layout: Some(layout),
226 })
227 }
228}
229
230trait StoreBody {
231 fn store_body(
232 &self,
233 to_cell: bool,
234 builder: &mut CellBuilder,
235 context: &mut dyn CellContext,
236 ) -> Result<(), Error>;
237}
238
239impl<'a> StoreBody for CellSlice<'a> {
240 fn store_body(
241 &self,
242 to_cell: bool,
243 builder: &mut CellBuilder,
244 context: &mut dyn CellContext,
245 ) -> Result<(), Error> {
246 SliceOrCell {
247 to_cell,
248 value: self,
249 }
250 .store_only_value_into(builder, context)
251 }
252}
253
254impl StoreBody for CellSliceParts {
255 fn store_body(
256 &self,
257 to_cell: bool,
258 builder: &mut CellBuilder,
259 context: &mut dyn CellContext,
260 ) -> Result<(), Error> {
261 let (cell, range) = self;
262 if to_cell && range.is_full(cell.as_ref()) {
263 builder.store_reference(cell.clone())
264 } else {
265 SliceOrCell {
266 to_cell,
267 value: ok!(range.apply(cell)),
268 }
269 .store_only_value_into(builder, context)
270 }
271 }
272}
273
274trait LoadBody<'a>: Sized {
275 fn load_body(from_cell: bool, slice: &mut CellSlice<'a>) -> Result<Self, Error>;
276}
277
278impl<'a> LoadBody<'a> for CellSlice<'a> {
279 fn load_body(from_cell: bool, slice: &mut CellSlice<'a>) -> Result<Self, Error> {
280 if from_cell {
281 slice.load_reference_as_slice()
282 } else {
283 Ok(slice.load_remaining())
284 }
285 }
286}
287
288impl<'a> LoadBody<'a> for CellSliceParts {
289 fn load_body(from_cell: bool, slice: &mut CellSlice<'a>) -> Result<Self, Error> {
290 let body = ok!(if from_cell {
291 slice.load_reference_cloned()
292 } else {
293 let slice = slice.load_remaining();
294 let mut builder = CellBuilder::new();
295 ok!(builder.store_slice(slice));
296 builder.build()
297 });
298
299 let range = CellSliceRange::full(body.as_ref());
300 Ok((body, range))
301 }
302}
303
304struct SliceOrCell<T> {
305 to_cell: bool,
306 value: T,
307}
308
309impl<T: Store> SliceOrCell<T> {
310 fn store_only_value_into(
311 &self,
312 builder: &mut CellBuilder,
313 context: &mut dyn CellContext,
314 ) -> Result<(), Error> {
315 if self.to_cell {
316 let cell = {
317 let mut builder = CellBuilder::new();
318 ok!(self.value.store_into(&mut builder, context));
319 ok!(builder.build_ext(context))
320 };
321 builder.store_reference(cell)
322 } else {
323 self.value.store_into(builder, context)
324 }
325 }
326}
327
328impl<T: Store> Store for SliceOrCell<T> {
329 fn store_into(
330 &self,
331 builder: &mut CellBuilder,
332 context: &mut dyn CellContext,
333 ) -> Result<(), Error> {
334 ok!(builder.store_bit(self.to_cell));
335 self.store_only_value_into(builder, context)
336 }
337}
338
339impl<'a, T: Load<'a>> Load<'a> for SliceOrCell<T> {
340 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
341 let to_cell = ok!(slice.load_bit());
342
343 let mut child_cell = if to_cell {
344 Some(ok!(slice.load_reference_as_slice()))
345 } else {
346 None
347 };
348
349 let slice = match &mut child_cell {
350 Some(slice) => slice,
351 None => slice,
352 };
353
354 Ok(Self {
355 to_cell,
356 value: ok!(T::load_from(slice)),
357 })
358 }
359}
360
361#[derive(Debug, Copy, Clone, Eq, PartialEq)]
363#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
364pub struct MessageLayout {
365 pub init_to_cell: bool,
367 pub body_to_cell: bool,
369}
370
371impl MessageLayout {
372 #[inline]
374 pub const fn plain() -> Self {
375 Self {
376 init_to_cell: false,
377 body_to_cell: false,
378 }
379 }
380
381 pub const fn compute_full_size(
383 &self,
384 info_size: Size,
385 init: Option<&StateInit>,
386 body_size: Size,
387 ) -> Size {
388 let l = DetailedMessageLayout::compute(info_size, init, body_size);
389
390 let mut total = l.info;
391
392 if self.init_to_cell {
394 total.refs += 1;
395 } else {
396 total.bits += l.init.bits;
397 total.refs += l.init.refs;
398 }
399
400 if self.body_to_cell {
402 total.refs += 1;
403 } else {
404 total.bits += l.body.bits;
405 total.refs += l.body.refs;
406 }
407
408 total
409 }
410
411 pub const fn compute(
414 info_size: Size,
415 init: Option<&StateInit>,
416 body_size: Size,
417 ) -> (Self, Size) {
418 let l = DetailedMessageLayout::compute(info_size, init, body_size);
419
420 let total_bits = l.info.bits + l.init.bits + l.body.bits;
422 let total_refs = l.info.refs + l.init.refs + l.body.refs;
423 if total_bits <= MAX_BIT_LEN && total_refs <= MAX_REF_COUNT as u8 {
424 let layout = Self {
425 init_to_cell: false,
426 body_to_cell: false,
427 };
428 return (
429 layout,
430 Size {
431 bits: total_bits,
432 refs: total_refs,
433 },
434 );
435 }
436
437 let total_bits = l.info.bits + l.init.bits;
439 let total_refs = l.info.refs + l.init.refs;
440 if total_bits <= MAX_BIT_LEN && total_refs < MAX_REF_COUNT as u8 {
441 let layout = Self {
442 init_to_cell: false,
443 body_to_cell: true,
444 };
445 return (
446 layout,
447 Size {
448 bits: total_bits,
449 refs: total_refs + 1,
450 },
451 );
452 }
453
454 let total_bits = l.info.bits + l.body.bits;
456 let total_refs = l.info.refs + l.body.refs;
457 if total_bits <= MAX_BIT_LEN && total_refs < MAX_REF_COUNT as u8 {
458 let layout = Self {
459 init_to_cell: true,
460 body_to_cell: false,
461 };
462 return (
463 layout,
464 Size {
465 bits: total_bits,
466 refs: total_refs + 1,
467 },
468 );
469 }
470
471 let layout = Self {
473 init_to_cell: true,
474 body_to_cell: true,
475 };
476 (
477 layout,
478 Size {
479 bits: l.info.bits,
480 refs: l.info.refs + 2,
481 },
482 )
483 }
484}
485
486struct DetailedMessageLayout {
487 info: Size,
488 init: Size,
489 body: Size,
490}
491
492impl DetailedMessageLayout {
493 const fn compute(mut info: Size, init: Option<&StateInit>, body: Size) -> Self {
494 info.bits += 2; let init = match init {
497 Some(init) => {
498 info.bits += 1; init.exact_size_const()
500 }
501 None => Size::ZERO,
502 };
503
504 Self { info, init, body }
505 }
506}
507
508#[derive(Debug, Clone, Eq, PartialEq)]
510#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
511#[cfg_attr(feature = "serde", serde(tag = "ty"))]
512pub enum RelaxedMsgInfo {
513 Int(RelaxedIntMsgInfo),
515 ExtOut(RelaxedExtOutMsgInfo),
517}
518
519impl RelaxedMsgInfo {
520 pub const fn exact_size_const(&self) -> Size {
522 Size {
523 bits: self.bit_len(),
524 refs: self.has_references() as u8,
525 }
526 }
527
528 const fn bit_len(&self) -> u16 {
530 match self {
531 Self::Int(info) => info.bit_len(),
532 Self::ExtOut(info) => info.bit_len(),
533 }
534 }
535
536 const fn has_references(&self) -> bool {
537 match self {
538 Self::Int(info) => !info.value.other.is_empty(),
539 _ => false,
540 }
541 }
542}
543
544impl ExactSize for RelaxedMsgInfo {
545 #[inline]
546 fn exact_size(&self) -> Size {
547 self.exact_size_const()
548 }
549}
550
551impl Store for RelaxedMsgInfo {
552 fn store_into(
553 &self,
554 builder: &mut CellBuilder,
555 context: &mut dyn CellContext,
556 ) -> Result<(), Error> {
557 match self {
558 Self::Int(info) => {
559 ok!(builder.store_bit_zero());
560 info.store_into(builder, context)
561 }
562 Self::ExtOut(info) => {
563 ok!(builder.store_small_uint(0b11, 2));
564 info.store_into(builder, context)
565 }
566 }
567 }
568}
569
570impl<'a> Load<'a> for RelaxedMsgInfo {
571 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
572 Ok(if !ok!(slice.load_bit()) {
573 match RelaxedIntMsgInfo::load_from(slice) {
574 Ok(info) => Self::Int(info),
575 Err(e) => return Err(e),
576 }
577 } else if ok!(slice.load_bit()) {
578 match RelaxedExtOutMsgInfo::load_from(slice) {
579 Ok(info) => Self::ExtOut(info),
580 Err(e) => return Err(e),
581 }
582 } else {
583 return Err(Error::InvalidTag);
584 })
585 }
586}
587
588#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
590pub enum MsgType {
591 Int,
593 ExtIn,
595 ExtOut,
597}
598
599impl MsgType {
600 pub const fn is_internal(&self) -> bool {
602 matches!(self, Self::Int)
603 }
604
605 pub const fn is_external_in(&self) -> bool {
607 matches!(self, Self::ExtIn)
608 }
609
610 pub const fn is_external_out(&self) -> bool {
612 matches!(self, Self::ExtOut)
613 }
614}
615
616impl Store for MsgType {
617 fn store_into(&self, b: &mut CellBuilder, _: &mut dyn CellContext) -> Result<(), Error> {
618 match self {
619 Self::Int => b.store_bit_zero(),
620 Self::ExtIn => b.store_small_uint(0b10, 2),
621 Self::ExtOut => b.store_small_uint(0b11, 2),
622 }
623 }
624}
625
626impl<'a> Load<'a> for MsgType {
627 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
628 Ok(if !ok!(slice.load_bit()) {
629 Self::Int
630 } else if !ok!(slice.load_bit()) {
631 Self::ExtIn
632 } else {
633 Self::ExtOut
634 })
635 }
636}
637
638#[derive(Debug, Clone, Eq, PartialEq)]
640#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
641#[cfg_attr(feature = "serde", serde(tag = "ty"))]
642pub enum MsgInfo {
643 Int(IntMsgInfo),
645 ExtIn(ExtInMsgInfo),
647 ExtOut(ExtOutMsgInfo),
649}
650
651impl MsgInfo {
652 pub const fn ty(&self) -> MsgType {
654 match self {
655 Self::Int(_) => MsgType::Int,
656 Self::ExtIn(_) => MsgType::ExtIn,
657 Self::ExtOut(_) => MsgType::ExtOut,
658 }
659 }
660
661 pub const fn is_internal(&self) -> bool {
663 matches!(self, Self::Int(_))
664 }
665
666 pub const fn is_external_in(&self) -> bool {
668 matches!(self, Self::ExtIn(_))
669 }
670
671 pub const fn is_external_out(&self) -> bool {
673 matches!(self, Self::ExtOut(_))
674 }
675
676 pub const fn exact_size_const(&self) -> Size {
678 Size {
679 bits: self.bit_len(),
680 refs: self.has_references() as u8,
681 }
682 }
683
684 const fn bit_len(&self) -> u16 {
686 match self {
687 Self::Int(info) => info.bit_len(),
688 Self::ExtIn(info) => info.bit_len(),
689 Self::ExtOut(info) => info.bit_len(),
690 }
691 }
692
693 const fn has_references(&self) -> bool {
694 match self {
695 Self::Int(info) => !info.value.other.is_empty(),
696 _ => false,
697 }
698 }
699}
700
701impl ExactSize for MsgInfo {
702 #[inline]
703 fn exact_size(&self) -> Size {
704 self.exact_size_const()
705 }
706}
707
708impl Store for MsgInfo {
709 fn store_into(
710 &self,
711 builder: &mut CellBuilder,
712 context: &mut dyn CellContext,
713 ) -> Result<(), Error> {
714 match self {
715 Self::Int(info) => {
716 ok!(builder.store_bit_zero());
717 info.store_into(builder, context)
718 }
719 Self::ExtIn(info) => {
720 ok!(builder.store_small_uint(0b10, 2));
721 info.store_into(builder, context)
722 }
723 Self::ExtOut(info) => {
724 ok!(builder.store_small_uint(0b11, 2));
725 info.store_into(builder, context)
726 }
727 }
728 }
729}
730
731impl<'a> Load<'a> for MsgInfo {
732 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
733 Ok(if !ok!(slice.load_bit()) {
734 match IntMsgInfo::load_from(slice) {
735 Ok(info) => Self::Int(info),
736 Err(e) => return Err(e),
737 }
738 } else if !ok!(slice.load_bit()) {
739 match ExtInMsgInfo::load_from(slice) {
740 Ok(info) => Self::ExtIn(info),
741 Err(e) => return Err(e),
742 }
743 } else {
744 match ExtOutMsgInfo::load_from(slice) {
745 Ok(info) => Self::ExtOut(info),
746 Err(e) => return Err(e),
747 }
748 })
749 }
750}
751
752#[derive(Debug, Clone, Eq, PartialEq)]
754#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
755pub struct IntMsgInfo {
756 pub ihr_disabled: bool,
758 pub bounce: bool,
760 pub bounced: bool,
762 pub src: IntAddr,
764 pub dst: IntAddr,
766 pub value: CurrencyCollection,
768 pub ihr_fee: Tokens,
772 pub fwd_fee: Tokens,
774 pub created_lt: u64,
776 pub created_at: u32,
778}
779
780impl Default for IntMsgInfo {
781 fn default() -> Self {
782 Self {
783 ihr_disabled: true,
784 bounce: false,
785 bounced: false,
786 src: Default::default(),
787 dst: Default::default(),
788 value: CurrencyCollection::ZERO,
789 ihr_fee: Default::default(),
790 fwd_fee: Default::default(),
791 created_lt: 0,
792 created_at: 0,
793 }
794 }
795}
796
797impl IntMsgInfo {
798 pub const fn bit_len(&self) -> u16 {
800 3 + self.src.bit_len()
801 + self.dst.bit_len()
802 + self.value.bit_len()
803 + self.ihr_fee.unwrap_bit_len()
804 + self.fwd_fee.unwrap_bit_len()
805 + 64
806 + 32
807 }
808}
809
810impl Store for IntMsgInfo {
811 fn store_into(
812 &self,
813 builder: &mut CellBuilder,
814 context: &mut dyn CellContext,
815 ) -> Result<(), Error> {
816 let flags =
817 ((self.ihr_disabled as u8) << 2) | ((self.bounce as u8) << 1) | self.bounced as u8;
818 ok!(builder.store_small_uint(flags, 3));
819 ok!(self.src.store_into(builder, context));
820 ok!(self.dst.store_into(builder, context));
821 ok!(self.value.store_into(builder, context));
822 ok!(self.ihr_fee.store_into(builder, context));
823 ok!(self.fwd_fee.store_into(builder, context));
824 ok!(builder.store_u64(self.created_lt));
825 builder.store_u32(self.created_at)
826 }
827}
828
829impl<'a> Load<'a> for IntMsgInfo {
830 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
831 let flags = ok!(slice.load_small_uint(3));
832 Ok(Self {
833 ihr_disabled: flags & 0b100 != 0,
834 bounce: flags & 0b010 != 0,
835 bounced: flags & 0b001 != 0,
836 src: ok!(IntAddr::load_from(slice)),
837 dst: ok!(IntAddr::load_from(slice)),
838 value: ok!(CurrencyCollection::load_from(slice)),
839 ihr_fee: ok!(Tokens::load_from(slice)),
840 fwd_fee: ok!(Tokens::load_from(slice)),
841 created_lt: ok!(slice.load_u64()),
842 created_at: ok!(slice.load_u32()),
843 })
844 }
845}
846
847#[derive(Debug, Clone, Eq, PartialEq)]
849#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
850pub struct RelaxedIntMsgInfo {
851 pub ihr_disabled: bool,
853 pub bounce: bool,
855 pub bounced: bool,
857 pub src: Option<IntAddr>,
859 pub dst: IntAddr,
861 pub value: CurrencyCollection,
863 pub ihr_fee: Tokens,
867 pub fwd_fee: Tokens,
869 pub created_lt: u64,
871 pub created_at: u32,
873}
874
875impl Default for RelaxedIntMsgInfo {
876 fn default() -> Self {
877 Self {
878 ihr_disabled: true,
879 bounce: false,
880 bounced: false,
881 src: Default::default(),
882 dst: Default::default(),
883 value: CurrencyCollection::ZERO,
884 ihr_fee: Default::default(),
885 fwd_fee: Default::default(),
886 created_lt: 0,
887 created_at: 0,
888 }
889 }
890}
891
892impl RelaxedIntMsgInfo {
893 pub const fn bit_len(&self) -> u16 {
895 3 + compute_opt_int_addr_bit_len(&self.src)
896 + self.dst.bit_len()
897 + self.value.bit_len()
898 + self.ihr_fee.unwrap_bit_len()
899 + self.fwd_fee.unwrap_bit_len()
900 + 64
901 + 32
902 }
903}
904
905impl Store for RelaxedIntMsgInfo {
906 fn store_into(
907 &self,
908 builder: &mut CellBuilder,
909 context: &mut dyn CellContext,
910 ) -> Result<(), Error> {
911 let flags =
912 ((self.ihr_disabled as u8) << 2) | ((self.bounce as u8) << 1) | self.bounced as u8;
913 ok!(builder.store_small_uint(flags, 3));
914 ok!(store_opt_int_addr(builder, context, &self.src));
915 ok!(self.dst.store_into(builder, context));
916 ok!(self.value.store_into(builder, context));
917 ok!(self.ihr_fee.store_into(builder, context));
918 ok!(self.fwd_fee.store_into(builder, context));
919 ok!(builder.store_u64(self.created_lt));
920 builder.store_u32(self.created_at)
921 }
922}
923
924impl<'a> Load<'a> for RelaxedIntMsgInfo {
925 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
926 let flags = ok!(slice.load_small_uint(3));
927 Ok(Self {
928 ihr_disabled: flags & 0b100 != 0,
929 bounce: flags & 0b010 != 0,
930 bounced: flags & 0b001 != 0,
931 src: ok!(load_opt_int_addr(slice)),
932 dst: ok!(IntAddr::load_from(slice)),
933 value: ok!(CurrencyCollection::load_from(slice)),
934 ihr_fee: ok!(Tokens::load_from(slice)),
935 fwd_fee: ok!(Tokens::load_from(slice)),
936 created_lt: ok!(slice.load_u64()),
937 created_at: ok!(slice.load_u32()),
938 })
939 }
940}
941
942#[derive(Debug, Default, Clone, Eq, PartialEq)]
944#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
945pub struct ExtInMsgInfo {
946 #[cfg_attr(
948 feature = "serde",
949 serde(default, skip_serializing_if = "Option::is_none")
950 )]
951 pub src: Option<ExtAddr>,
952 pub dst: IntAddr,
954 pub import_fee: Tokens,
958}
959
960impl ExtInMsgInfo {
961 pub const fn bit_len(&self) -> u16 {
963 2 + compute_ext_addr_bit_len(&self.src)
964 + self.dst.bit_len()
965 + self.import_fee.unwrap_bit_len()
966 }
967}
968
969impl Store for ExtInMsgInfo {
970 fn store_into(
971 &self,
972 builder: &mut CellBuilder,
973 context: &mut dyn CellContext,
974 ) -> Result<(), Error> {
975 if !self.import_fee.is_valid() {
976 return Err(Error::InvalidData);
977 }
978 if !builder.has_capacity(self.bit_len(), 0) {
979 return Err(Error::CellOverflow);
980 }
981 ok!(store_ext_addr(builder, context, &self.src));
982 ok!(self.dst.store_into(builder, context));
983 self.import_fee.store_into(builder, context)
984 }
985}
986
987impl<'a> Load<'a> for ExtInMsgInfo {
988 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
989 Ok(Self {
990 src: ok!(load_ext_addr(slice)),
991 dst: ok!(IntAddr::load_from(slice)),
992 import_fee: ok!(Tokens::load_from(slice)),
993 })
994 }
995}
996
997#[derive(Debug, Default, Clone, Eq, PartialEq)]
999#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1000pub struct ExtOutMsgInfo {
1001 pub src: IntAddr,
1003 #[cfg_attr(
1005 feature = "serde",
1006 serde(default, skip_serializing_if = "Option::is_none")
1007 )]
1008 pub dst: Option<ExtAddr>,
1009 pub created_lt: u64,
1011 pub created_at: u32,
1013}
1014
1015impl ExtOutMsgInfo {
1016 pub const fn bit_len(&self) -> u16 {
1018 2 + self.src.bit_len() + compute_ext_addr_bit_len(&self.dst) + 64 + 32
1019 }
1020}
1021
1022impl Store for ExtOutMsgInfo {
1023 fn store_into(
1024 &self,
1025 builder: &mut CellBuilder,
1026 context: &mut dyn CellContext,
1027 ) -> Result<(), Error> {
1028 if !builder.has_capacity(self.bit_len(), 0) {
1029 return Err(Error::CellOverflow);
1030 }
1031 ok!(self.src.store_into(builder, context));
1032 ok!(store_ext_addr(builder, context, &self.dst));
1033 ok!(builder.store_u64(self.created_lt));
1034 builder.store_u32(self.created_at)
1035 }
1036}
1037
1038impl<'a> Load<'a> for ExtOutMsgInfo {
1039 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
1040 Ok(Self {
1041 src: ok!(IntAddr::load_from(slice)),
1042 dst: ok!(load_ext_addr(slice)),
1043 created_lt: ok!(slice.load_u64()),
1044 created_at: ok!(slice.load_u32()),
1045 })
1046 }
1047}
1048
1049#[derive(Debug, Default, Clone, Eq, PartialEq)]
1051#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1052pub struct RelaxedExtOutMsgInfo {
1053 pub src: Option<IntAddr>,
1055 #[cfg_attr(
1057 feature = "serde",
1058 serde(default, skip_serializing_if = "Option::is_none")
1059 )]
1060 pub dst: Option<ExtAddr>,
1061 pub created_lt: u64,
1063 pub created_at: u32,
1065}
1066
1067impl RelaxedExtOutMsgInfo {
1068 pub const fn bit_len(&self) -> u16 {
1070 2 + compute_opt_int_addr_bit_len(&self.src) + compute_ext_addr_bit_len(&self.dst) + 64 + 32
1071 }
1072}
1073
1074impl Store for RelaxedExtOutMsgInfo {
1075 fn store_into(
1076 &self,
1077 builder: &mut CellBuilder,
1078 context: &mut dyn CellContext,
1079 ) -> Result<(), Error> {
1080 ok!(store_opt_int_addr(builder, context, &self.src));
1081 ok!(store_ext_addr(builder, context, &self.dst));
1082 ok!(builder.store_u64(self.created_lt));
1083 builder.store_u32(self.created_at)
1084 }
1085}
1086
1087impl<'a> Load<'a> for RelaxedExtOutMsgInfo {
1088 fn load_from(slice: &mut CellSlice<'a>) -> Result<Self, Error> {
1089 Ok(Self {
1090 src: ok!(load_opt_int_addr(slice)),
1091 dst: ok!(load_ext_addr(slice)),
1092 created_lt: ok!(slice.load_u64()),
1093 created_at: ok!(slice.load_u32()),
1094 })
1095 }
1096}
1097
1098const fn compute_ext_addr_bit_len(addr: &Option<ExtAddr>) -> u16 {
1099 match addr {
1100 Some(addr) => 2 + addr.bit_len(),
1101 None => 2,
1102 }
1103}
1104
1105fn store_ext_addr(
1106 builder: &mut CellBuilder,
1107 context: &mut dyn CellContext,
1108 addr: &Option<ExtAddr>,
1109) -> Result<(), Error> {
1110 match addr {
1111 None => builder.store_zeros(2),
1112 Some(ExtAddr { data_bit_len, data }) => {
1113 if !builder.has_capacity(2 + Uint9::BITS + data_bit_len.into_inner(), 0) {
1114 return Err(Error::CellOverflow);
1115 }
1116 ok!(builder.store_bit_zero());
1117 ok!(builder.store_bit_one());
1118 ok!(data_bit_len.store_into(builder, context));
1119 builder.store_raw(data, data_bit_len.into_inner())
1120 }
1121 }
1122}
1123
1124fn load_ext_addr(slice: &mut CellSlice<'_>) -> Result<Option<ExtAddr>, Error> {
1125 if ok!(slice.load_bit()) {
1126 return Err(Error::InvalidTag);
1127 }
1128
1129 if !ok!(slice.load_bit()) {
1130 return Ok(None);
1131 }
1132
1133 let data_bit_len = ok!(Uint9::load_from(slice));
1134 if !slice.has_remaining(data_bit_len.into_inner(), 0) {
1135 return Err(Error::CellUnderflow);
1136 }
1137
1138 let mut data = vec![0; (data_bit_len.into_inner() as usize + 7) / 8];
1139 ok!(slice.load_raw(&mut data, data_bit_len.into_inner()));
1140 Ok(Some(ExtAddr { data_bit_len, data }))
1141}
1142
1143const fn compute_opt_int_addr_bit_len(addr: &Option<IntAddr>) -> u16 {
1144 match addr {
1145 Some(src) => src.bit_len(),
1146 None => 2,
1147 }
1148}
1149
1150fn store_opt_int_addr(
1151 builder: &mut CellBuilder,
1152 context: &mut dyn CellContext,
1153 addr: &Option<IntAddr>,
1154) -> Result<(), Error> {
1155 match addr {
1156 Some(addr) => addr.store_into(builder, context),
1157 None => builder.store_zeros(2),
1158 }
1159}
1160
1161fn load_opt_int_addr(slice: &mut CellSlice<'_>) -> Result<Option<IntAddr>, Error> {
1162 if ok!(slice.get_bit(0)) {
1163 IntAddr::load_from(slice).map(Some)
1164 } else if ok!(slice.load_small_uint(2)) == 0b00 {
1165 Ok(None)
1166 } else {
1167 Err(Error::InvalidTag)
1168 }
1169}