ferrum_interfaces/vnext/operation/
storage_profile.rs1use serde::{Deserialize, Deserializer, Serialize};
2
3use super::super::VNextError;
4use super::foundation::invalid_operation;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
7#[serde(rename_all = "snake_case")]
8pub enum ElementType {
9 Bool,
10 U8,
11 U32,
12 I8,
13 I32,
14 F16,
15 Bf16,
16 F32,
17}
18
19impl ElementType {
20 pub const fn size_bytes(self) -> u64 {
21 match self {
22 Self::Bool | Self::U8 | Self::I8 => 1,
23 Self::F16 | Self::Bf16 => 2,
24 Self::U32 | Self::I32 | Self::F32 => 4,
25 }
26 }
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
30#[serde(rename_all = "snake_case")]
31pub enum DynamicStorageAllocator {
32 LinearArena,
33 FixedBlockArena { block_bytes: u64 },
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
37#[serde(rename_all = "snake_case")]
38pub enum DynamicStorageView {
39 Contiguous,
40 PagedRegions { block_bytes: u64 },
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
46pub struct DynamicStorageProfile {
47 allocator: DynamicStorageAllocator,
48 view: DynamicStorageView,
49}
50
51impl DynamicStorageProfile {
52 pub fn new(
53 allocator: DynamicStorageAllocator,
54 view: DynamicStorageView,
55 ) -> Result<Self, VNextError> {
56 let valid = match (allocator, view) {
57 (DynamicStorageAllocator::LinearArena, DynamicStorageView::Contiguous) => true,
58 (
59 DynamicStorageAllocator::FixedBlockArena { block_bytes },
60 DynamicStorageView::Contiguous,
61 ) => block_bytes.is_power_of_two(),
62 (
63 DynamicStorageAllocator::FixedBlockArena {
64 block_bytes: allocator_block,
65 },
66 DynamicStorageView::PagedRegions {
67 block_bytes: view_block,
68 },
69 ) => allocator_block.is_power_of_two() && allocator_block == view_block,
70 (DynamicStorageAllocator::LinearArena, DynamicStorageView::PagedRegions { .. }) => {
71 false
72 }
73 };
74 if !valid {
75 return Err(invalid_operation(
76 "dynamic storage allocator/view profile is incompatible or invalid",
77 ));
78 }
79 Ok(Self { allocator, view })
80 }
81
82 pub const fn allocator(self) -> DynamicStorageAllocator {
83 self.allocator
84 }
85
86 pub const fn view(self) -> DynamicStorageView {
87 self.view
88 }
89}
90
91#[derive(Deserialize)]
92#[serde(deny_unknown_fields)]
93struct DynamicStorageProfileWire {
94 allocator: DynamicStorageAllocator,
95 view: DynamicStorageView,
96}
97
98impl<'de> Deserialize<'de> for DynamicStorageProfile {
99 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
100 where
101 D: Deserializer<'de>,
102 {
103 let wire = DynamicStorageProfileWire::deserialize(deserializer)?;
104 Self::new(wire.allocator, wire.view).map_err(serde::de::Error::custom)
105 }
106}
107
108#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
112pub struct DynamicStorageRequirement {
113 accepted_profiles: Vec<DynamicStorageProfile>,
114}
115
116impl DynamicStorageRequirement {
117 pub fn new(mut accepted_profiles: Vec<DynamicStorageProfile>) -> Result<Self, VNextError> {
118 accepted_profiles.sort_unstable();
119 accepted_profiles.dedup();
120 if accepted_profiles.is_empty() {
121 return Err(invalid_operation(
122 "dynamic storage requirement has no accepted profile",
123 ));
124 }
125 Ok(Self { accepted_profiles })
126 }
127
128 pub fn contiguous() -> Self {
129 Self {
130 accepted_profiles: vec![DynamicStorageProfile {
131 allocator: DynamicStorageAllocator::LinearArena,
132 view: DynamicStorageView::Contiguous,
133 }],
134 }
135 }
136
137 pub fn accepted_profiles(&self) -> &[DynamicStorageProfile] {
138 &self.accepted_profiles
139 }
140
141 pub fn accepts(&self, profile: DynamicStorageProfile) -> bool {
142 self.accepted_profiles.binary_search(&profile).is_ok()
143 }
144}
145
146#[derive(Deserialize)]
147#[serde(deny_unknown_fields)]
148struct DynamicStorageRequirementWire {
149 accepted_profiles: Vec<DynamicStorageProfile>,
150}
151
152impl<'de> Deserialize<'de> for DynamicStorageRequirement {
153 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
154 where
155 D: Deserializer<'de>,
156 {
157 let wire = DynamicStorageRequirementWire::deserialize(deserializer)?;
158 let original = wire.accepted_profiles.clone();
159 let requirement = Self::new(wire.accepted_profiles).map_err(serde::de::Error::custom)?;
160 if requirement.accepted_profiles != original {
161 return Err(serde::de::Error::custom(
162 "dynamic storage requirement profiles are not canonical and unique",
163 ));
164 }
165 Ok(requirement)
166 }
167}