freenet_stdlib/contract_interface/
update.rs1use std::collections::HashMap;
7
8use serde::{Deserialize, Serialize};
9
10use crate::client_api::{TryFromFbs, WsApiError};
11use crate::common_generated::common::{UpdateData as FbsUpdateData, UpdateDataType};
12use crate::generated::client_request::RelatedContracts as FbsRelatedContracts;
13
14use super::{ContractError, ContractInstanceId, State, StateDelta, CONTRACT_KEY_SIZE};
15
16#[non_exhaustive]
19#[derive(Debug, Serialize, Deserialize)]
20pub struct UpdateModification<'a> {
21 #[serde(borrow)]
22 pub new_state: Option<State<'a>>,
23 pub related: Vec<RelatedContract>,
25}
26
27impl<'a> UpdateModification<'a> {
28 pub fn valid(new_state: State<'a>) -> Self {
30 Self {
31 new_state: Some(new_state),
32 related: vec![],
33 }
34 }
35
36 pub fn unwrap_valid(self) -> State<'a> {
40 match self.new_state {
41 Some(s) => s,
42 _ => panic!("failed unwrapping state in modification"),
43 }
44 }
45}
46
47impl UpdateModification<'_> {
48 pub fn requires(related: Vec<RelatedContract>) -> Result<Self, ContractError> {
51 if related.is_empty() {
52 return Err(ContractError::InvalidUpdateWithInfo {
53 reason: "At least one related contract is required".into(),
54 });
55 }
56 Ok(Self {
57 new_state: None,
58 related,
59 })
60 }
61
62 pub fn get_related(&self) -> &[RelatedContract] {
64 &self.related
65 }
66
67 pub fn into_owned(self) -> UpdateModification<'static> {
69 let Self { new_state, related } = self;
70 UpdateModification {
71 new_state: new_state.map(State::into_owned),
72 related,
73 }
74 }
75
76 pub fn requires_dependencies(&self) -> bool {
77 !self.related.is_empty()
78 }
79}
80
81#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
85pub struct RelatedContracts<'a> {
86 #[serde(borrow)]
87 map: HashMap<ContractInstanceId, Option<State<'a>>>,
88}
89
90impl RelatedContracts<'_> {
91 pub fn new() -> Self {
92 Self {
93 map: HashMap::new(),
94 }
95 }
96
97 pub fn into_owned(self) -> RelatedContracts<'static> {
99 let mut map = HashMap::with_capacity(self.map.len());
100 for (k, v) in self.map {
101 map.insert(k, v.map(|s| s.into_owned()));
102 }
103 RelatedContracts { map }
104 }
105
106 pub fn deser_related_contracts<'de, D>(deser: D) -> Result<RelatedContracts<'static>, D::Error>
107 where
108 D: serde::Deserializer<'de>,
109 {
110 let value = <RelatedContracts as Deserialize>::deserialize(deser)?;
111 Ok(value.into_owned())
112 }
113}
114
115impl RelatedContracts<'static> {
116 pub fn states(&self) -> impl Iterator<Item = (&ContractInstanceId, &Option<State<'static>>)> {
117 self.map.iter()
118 }
119}
120
121impl<'a> RelatedContracts<'a> {
122 pub fn update(
123 &mut self,
124 ) -> impl Iterator<Item = (&ContractInstanceId, &mut Option<State<'a>>)> + '_ {
125 self.map.iter_mut()
126 }
127
128 pub fn missing(&mut self, contracts: Vec<ContractInstanceId>) {
129 for key in contracts {
130 self.map.entry(key).or_default();
131 }
132 }
133}
134
135impl<'a> TryFromFbs<&FbsRelatedContracts<'a>> for RelatedContracts<'a> {
136 fn try_decode_fbs(related_contracts: &FbsRelatedContracts<'a>) -> Result<Self, WsApiError> {
137 let mut map = HashMap::with_capacity(related_contracts.contracts().len());
138 for related in related_contracts.contracts().iter() {
139 let id = ContractInstanceId::from_bytes(related.instance_id().data().bytes()).unwrap();
140 let state = State::from(related.state().bytes());
141 map.insert(id, Some(state));
142 }
143 Ok(RelatedContracts::from(map))
144 }
145}
146
147impl<'a> From<HashMap<ContractInstanceId, Option<State<'a>>>> for RelatedContracts<'a> {
148 fn from(related_contracts: HashMap<ContractInstanceId, Option<State<'a>>>) -> Self {
149 Self {
150 map: related_contracts,
151 }
152 }
153}
154
155#[derive(Debug, Serialize, Deserialize)]
158pub struct RelatedContract {
159 pub contract_instance_id: ContractInstanceId,
160 pub mode: RelatedMode,
161 }
163
164#[derive(Debug, Serialize, Deserialize)]
166pub enum RelatedMode {
167 StateOnce,
169 StateThenSubscribe,
171}
172
173#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
175pub enum ValidateResult {
176 Valid,
177 Invalid,
178 RequestRelated(Vec<ContractInstanceId>),
181}
182
183#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
185pub enum UpdateData<'a> {
186 State(#[serde(borrow)] State<'a>),
187 Delta(#[serde(borrow)] StateDelta<'a>),
188 StateAndDelta {
189 #[serde(borrow)]
190 state: State<'a>,
191 #[serde(borrow)]
192 delta: StateDelta<'a>,
193 },
194 RelatedState {
195 related_to: ContractInstanceId,
196 #[serde(borrow)]
197 state: State<'a>,
198 },
199 RelatedDelta {
200 related_to: ContractInstanceId,
201 #[serde(borrow)]
202 delta: StateDelta<'a>,
203 },
204 RelatedStateAndDelta {
205 related_to: ContractInstanceId,
206 #[serde(borrow)]
207 state: State<'a>,
208 #[serde(borrow)]
209 delta: StateDelta<'a>,
210 },
211}
212
213impl UpdateData<'_> {
214 pub fn size(&self) -> usize {
215 match self {
216 UpdateData::State(state) => state.size(),
217 UpdateData::Delta(delta) => delta.size(),
218 UpdateData::StateAndDelta { state, delta } => state.size() + delta.size(),
219 UpdateData::RelatedState { state, .. } => state.size() + CONTRACT_KEY_SIZE,
220 UpdateData::RelatedDelta { delta, .. } => delta.size() + CONTRACT_KEY_SIZE,
221 UpdateData::RelatedStateAndDelta { state, delta, .. } => {
222 state.size() + delta.size() + CONTRACT_KEY_SIZE
223 }
224 }
225 }
226
227 pub fn unwrap_delta(&self) -> &StateDelta<'_> {
228 match self {
229 UpdateData::Delta(delta) => delta,
230 _ => panic!(),
231 }
232 }
233
234 pub fn into_owned(self) -> UpdateData<'static> {
236 match self {
237 UpdateData::State(s) => UpdateData::State(State::from(s.into_bytes())),
238 UpdateData::Delta(d) => UpdateData::Delta(StateDelta::from(d.into_bytes())),
239 UpdateData::StateAndDelta { state, delta } => UpdateData::StateAndDelta {
240 delta: StateDelta::from(delta.into_bytes()),
241 state: State::from(state.into_bytes()),
242 },
243 UpdateData::RelatedState { related_to, state } => UpdateData::RelatedState {
244 related_to,
245 state: State::from(state.into_bytes()),
246 },
247 UpdateData::RelatedDelta { related_to, delta } => UpdateData::RelatedDelta {
248 related_to,
249 delta: StateDelta::from(delta.into_bytes()),
250 },
251 UpdateData::RelatedStateAndDelta {
252 related_to,
253 state,
254 delta,
255 } => UpdateData::RelatedStateAndDelta {
256 related_to,
257 state: State::from(state.into_bytes()),
258 delta: StateDelta::from(delta.into_bytes()),
259 },
260 }
261 }
262
263 pub(crate) fn get_self_states<'a>(
264 updates: &[UpdateData<'a>],
265 ) -> Vec<(Option<State<'a>>, Option<StateDelta<'a>>)> {
266 let mut own_states = Vec::with_capacity(updates.len());
267 for update in updates {
268 match update {
269 UpdateData::State(state) => own_states.push((Some(state.clone()), None)),
270 UpdateData::Delta(delta) => own_states.push((None, Some(delta.clone()))),
271 UpdateData::StateAndDelta { state, delta } => {
272 own_states.push((Some(state.clone()), Some(delta.clone())))
273 }
274 _ => {}
275 }
276 }
277 own_states
278 }
279
280 pub(crate) fn deser_update_data<'de, D>(deser: D) -> Result<UpdateData<'static>, D::Error>
281 where
282 D: serde::Deserializer<'de>,
283 {
284 let value = <UpdateData as Deserialize>::deserialize(deser)?;
285 Ok(value.into_owned())
286 }
287}
288
289impl<'a> From<StateDelta<'a>> for UpdateData<'a> {
290 fn from(delta: StateDelta<'a>) -> Self {
291 UpdateData::Delta(delta)
292 }
293}
294
295impl<'a> TryFromFbs<&FbsUpdateData<'a>> for UpdateData<'a> {
296 fn try_decode_fbs(update_data: &FbsUpdateData<'a>) -> Result<Self, WsApiError> {
297 match update_data.update_data_type() {
298 UpdateDataType::StateUpdate => {
299 let update = update_data.update_data_as_state_update().unwrap();
300 let state = State::from(update.state().bytes());
301 Ok(UpdateData::State(state))
302 }
303 UpdateDataType::DeltaUpdate => {
304 let update = update_data.update_data_as_delta_update().unwrap();
305 let delta = StateDelta::from(update.delta().bytes());
306 Ok(UpdateData::Delta(delta))
307 }
308 UpdateDataType::StateAndDeltaUpdate => {
309 let update = update_data.update_data_as_state_and_delta_update().unwrap();
310 let state = State::from(update.state().bytes());
311 let delta = StateDelta::from(update.delta().bytes());
312 Ok(UpdateData::StateAndDelta { state, delta })
313 }
314 UpdateDataType::RelatedStateUpdate => {
315 let update = update_data.update_data_as_related_state_update().unwrap();
316 let state = State::from(update.state().bytes());
317 let related_to =
318 ContractInstanceId::from_bytes(update.related_to().data().bytes()).unwrap();
319 Ok(UpdateData::RelatedState { related_to, state })
320 }
321 UpdateDataType::RelatedDeltaUpdate => {
322 let update = update_data.update_data_as_related_delta_update().unwrap();
323 let delta = StateDelta::from(update.delta().bytes());
324 let related_to =
325 ContractInstanceId::from_bytes(update.related_to().data().bytes()).unwrap();
326 Ok(UpdateData::RelatedDelta { related_to, delta })
327 }
328 UpdateDataType::RelatedStateAndDeltaUpdate => {
329 let update = update_data
330 .update_data_as_related_state_and_delta_update()
331 .unwrap();
332 let state = State::from(update.state().bytes());
333 let delta = StateDelta::from(update.delta().bytes());
334 let related_to =
335 ContractInstanceId::from_bytes(update.related_to().data().bytes()).unwrap();
336 Ok(UpdateData::RelatedStateAndDelta {
337 related_to,
338 state,
339 delta,
340 })
341 }
342 _ => unreachable!(),
343 }
344 }
345}