Skip to main content

co_api/library/
guard.rs

1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (C) 2026 1io BRANDGUARDIAN GmbH
3
4use crate::{
5	library::{
6		data::{read_input_sync, write_output_sync},
7		wasm_storage::WasmStorage,
8	},
9	Guard,
10};
11use co_primitives::{CoreBlockStorage, GuardInput, GuardOutput, RawCid, Tags};
12use futures::{executor::LocalPool, future::LocalBoxFuture, task::LocalSpawnExt, FutureExt};
13use std::sync::Arc;
14
15pub fn guard<R>(input: &RawCid, output: &mut RawCid)
16where
17	R: Guard + 'static,
18{
19	let mut storage = WasmStorage::new();
20	let block_storage = CoreBlockStorage::new(storage.clone(), false);
21
22	// input
23	let guard_input: GuardInput = read_input_sync(&storage, input);
24
25	// execute
26	let guard_output = GuardRef::new::<R>().execute_blocking(guard_input, block_storage);
27
28	// output
29	write_output_sync(&mut storage, &guard_output, output);
30}
31
32#[allow(clippy::type_complexity)]
33pub struct GuardRef(
34	Arc<dyn Fn(GuardInput, CoreBlockStorage) -> LocalBoxFuture<'static, GuardOutput> + Sync + Send + 'static>,
35);
36impl GuardRef {
37	pub fn new<R>() -> Self
38	where
39		R: Guard + 'static,
40	{
41		Self(Arc::new(|input, storage| {
42			async move {
43				match R::verify(&storage, input.guard, input.state, input.heads, input.next_head).await {
44					Ok(valid) => GuardOutput { result: valid, error: None, tags: Tags::default() },
45					Err(err) => GuardOutput { result: false, error: Some(err.to_string()), tags: Tags::default() },
46				}
47			}
48			.boxed_local()
49		}))
50	}
51
52	pub fn execute_blocking(&self, input: GuardInput, storage: CoreBlockStorage) -> GuardOutput {
53		let mut pool = LocalPool::new();
54		let handle = pool
55			.spawner()
56			.spawn_local_with_handle({
57				let execute = self.0.clone();
58				async move { execute(input, storage).await }
59			})
60			.expect("future to execute");
61		pool.run_until(handle)
62	}
63
64	pub async fn execute_async(&self, input: GuardInput, storage: CoreBlockStorage) -> GuardOutput {
65		(self.0)(input, storage).await
66	}
67}
68impl Clone for GuardRef {
69	fn clone(&self) -> Self {
70		Self(self.0.clone())
71	}
72}