Skip to main content

platform_data/
constants.rs

1use std::ops::RangeInclusive;
2
3use crate::Hybrid;
4use platform_num::LinkReference;
5
6#[derive(Clone, Eq, PartialEq, Debug)]
7pub struct LinksConstants<T: LinkReference> {
8    pub index_part: T,
9    pub source_part: T,
10    pub target_part: T,
11    pub null: T,
12    pub r#continue: T,
13    pub r#break: T,
14    pub skip: T,
15    pub any: T,
16    pub itself: T,
17    pub error: T,
18    pub internal_range: RangeInclusive<T>,
19    pub external_range: Option<RangeInclusive<T>>,
20}
21
22impl<T: LinkReference> LinksConstants<T> {
23    fn default_target_part() -> T {
24        T::from_byte(2)
25    }
26
27    /// Creates constants with custom ranges, reserving the last six internal values for service constants.
28    ///
29    /// # Panics
30    ///
31    /// Panics if the external range overlaps the supplied internal range, including its service values.
32    pub fn full_new(
33        target_part: T,
34        internal: RangeInclusive<T>,
35        external: Option<RangeInclusive<T>>,
36    ) -> Self {
37        if let Some(external) = external.as_ref() {
38            assert!(
39                external.is_empty()
40                    || external.end() < internal.start()
41                    || external.start() > internal.end(),
42                "external range must not overlap the internal range or reserved service values"
43            );
44        }
45
46        Self {
47            index_part: T::from_byte(0),
48            source_part: T::from_byte(1),
49            target_part,
50            null: T::from_byte(0),
51            r#continue: *internal.end(),
52            r#break: *internal.end() - T::from_byte(1),
53            skip: *internal.end() - T::from_byte(2),
54            any: *internal.end() - T::from_byte(3),
55            itself: *internal.end() - T::from_byte(4),
56            error: *internal.end() - T::from_byte(5),
57            internal_range: *internal.start()..=*internal.end() - T::from_byte(6),
58            external_range: external,
59        }
60    }
61
62    // TODO: enough for now
63    pub fn via_external(target_part: T, external: bool) -> Self {
64        Self::full_new(
65            target_part,
66            Self::default_internal(external),
67            Self::default_external(external),
68        )
69    }
70
71    /// Creates constants with the default target part and custom ranges.
72    ///
73    /// # Panics
74    ///
75    /// Panics if the external range overlaps the supplied internal range, including its service values.
76    pub fn via_ranges(internal: RangeInclusive<T>, external: Option<RangeInclusive<T>>) -> Self {
77        Self::full_new(Self::default_target_part(), internal, external)
78    }
79
80    #[must_use]
81    pub fn via_only_external(external: bool) -> Self {
82        Self::via_external(Self::default_target_part(), external)
83    }
84
85    /// Creates constants with external references starting immediately after the service values.
86    #[must_use]
87    pub fn external() -> Self {
88        Self::via_only_external(true)
89    }
90
91    #[must_use]
92    pub fn internal() -> Self {
93        Self::via_only_external(false)
94    }
95
96    #[must_use]
97    pub fn new() -> Self {
98        Self::internal()
99    }
100
101    fn default_internal(external: bool) -> RangeInclusive<T> {
102        if external {
103            T::from_byte(1)..=Hybrid::half()
104        } else {
105            T::from_byte(1)..=T::MAX
106        }
107    }
108
109    fn default_external(external: bool) -> Option<RangeInclusive<T>> {
110        if external {
111            Some(Hybrid::<T>::half() + T::from_byte(1)..=T::MAX)
112        } else {
113            None
114        }
115    }
116
117    pub fn is_internal(&self, address: T) -> bool {
118        self.internal_range.contains(&address)
119    }
120
121    pub fn is_external(&self, address: T) -> bool {
122        self.external_range
123            .clone()
124            .is_some_and(|range| range.contains(&address))
125    }
126
127    pub fn is_reference(&self, address: T) -> bool {
128        self.is_internal(address) || self.is_external(address)
129    }
130}
131
132impl<T: LinkReference> Default for LinksConstants<T> {
133    fn default() -> Self {
134        Self::new()
135    }
136}