1use std::fmt;
16use std::fmt::{Display, Formatter};
17use std::str::FromStr;
18
19#[cfg(test)]
20test_r::enable!();
21
22pub use uuid::Uuid;
23
24pub mod bindings {
25 use wit_bindgen::generate;
26
27 generate!({
28 path: "wit",
29 world: "golem-rust",
30 generate_all,
31 generate_unused_types: true,
32 pub_export_macro: true,
33 with: {
34 "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
35 "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
36 "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
37 }
38 });
39}
40
41#[cfg(feature = "export_load_snapshot")]
42pub mod load_snapshot {
43 use wit_bindgen::generate;
44
45 generate!({
46 path: "wit",
47 world: "golem-rust-load-snapshot",
48 generate_all,
49 generate_unused_types: true,
50 pub_export_macro: true,
51 with: {
52 "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
53 "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
54 "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
55
56 "golem:api/host@1.3.0": crate::bindings::golem::api::host,
57 "golem:api/oplog@1.3.0": crate::bindings::golem::api::oplog,
58 "golem:api/context@1.3.0": crate::bindings::golem::api::context,
59 "golem:durability/durability@1.3.0": crate::bindings::golem::durability::durability,
60 "golem:rdbms/mysql@0.0.1": crate::bindings::golem::rdbms::mysql,
61 "golem:rdbms/postgres@0.0.1": crate::bindings::golem::rdbms::postgres,
62 "golem:rdbms/types@0.0.1": crate::bindings::golem::rdbms::types,
63 "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
64 "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
65 "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
66 "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
67 "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
68 "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
69 "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
70 "wasi:logging/logging": crate::bindings::wasi::logging::logging,
71 }
72 });
73
74 pub use __export_golem_rust_load_snapshot_impl as export_load_snapshot;
75}
76
77#[cfg(feature = "export_save_snapshot")]
78pub mod save_snapshot {
79 use wit_bindgen::generate;
80
81 generate!({
82 path: "wit",
83 world: "golem-rust-save-snapshot",
84 generate_all,
85 generate_unused_types: true,
86 pub_export_macro: true,
87 with: {
88 "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
89 "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
90 "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
91
92 "golem:api/host@1.3.0": crate::bindings::golem::api::host,
93 "golem:api/oplog@1.3.0": crate::bindings::golem::api::oplog,
94 "golem:api/context@1.3.0": crate::bindings::golem::api::context,
95 "golem:durability/durability@1.3.0": crate::bindings::golem::durability::durability,
96 "golem:rdbms/mysql@0.0.1": crate::bindings::golem::rdbms::mysql,
97 "golem:rdbms/postgres@0.0.1": crate::bindings::golem::rdbms::postgres,
98 "golem:rdbms/types@0.0.1": crate::bindings::golem::rdbms::types,
99 "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
100 "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
101 "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
102 "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
103 "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
104 "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
105 "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
106 "wasi:logging/logging": crate::bindings::wasi::logging::logging,
107 }
108 });
109
110 pub use __export_golem_rust_save_snapshot_impl as export_save_snapshot;
111}
112
113#[cfg(feature = "export_golem_agentic")]
114pub mod golem_agentic {
115 use wit_bindgen::generate;
116
117 generate!({
118 path: "wit",
119 world: "golem-agentic",
120 generate_all,
121 generate_unused_types: true,
122 pub_export_macro: true,
123 with: {
124 "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
125 "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
126 "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
127
128 "golem:api/host@1.3.0": crate::bindings::golem::api::host,
129 "golem:api/oplog@1.3.0": crate::bindings::golem::api::oplog,
130 "golem:api/context@1.3.0": crate::bindings::golem::api::context,
131 "golem:durability/durability@1.3.0": crate::bindings::golem::durability::durability,
132 "golem:rdbms/mysql@0.0.1": crate::bindings::golem::rdbms::mysql,
133 "golem:rdbms/postgres@0.0.1": crate::bindings::golem::rdbms::postgres,
134 "golem:rdbms/types@0.0.1": crate::bindings::golem::rdbms::types,
135 "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
136 "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
137 "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
138 "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
139 "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
140 "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
141 "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
142 "wasi:logging/logging": crate::bindings::wasi::logging::logging,
143 }
144 });
145
146 pub use __export_golem_agentic_impl as export_golem_agentic;
147}
148
149#[cfg(feature = "golem_ai")]
150pub mod golem_ai {
151 use wit_bindgen::generate;
152 generate!({
153 path: "wit",
154 world: "golem-ai",
155 generate_all,
156 generate_unused_types: true,
157 additional_derives: [crate::Schema],
158 pub_export_macro: true,
159 with: {
160 "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
161 "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
162 "wasi:io/error@0.2.3": wstd::wasi::io::error,
163 "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
164
165 "golem:api/host@1.3.0": crate::bindings::golem::api::host,
166 "golem:api/oplog@1.3.0": crate::bindings::golem::api::oplog,
167 "golem:api/context@1.3.0": crate::bindings::golem::api::context,
168 "golem:durability/durability@1.3.0": crate::bindings::golem::durability::durability,
169 "golem:rdbms/mysql@0.0.1": crate::bindings::golem::rdbms::mysql,
170 "golem:rdbms/postgres@0.0.1": crate::bindings::golem::rdbms::postgres,
171 "golem:rdbms/types@0.0.1": crate::bindings::golem::rdbms::types,
172 "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
173 "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
174 "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
175 "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
176 "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
177 "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
178 "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
179 "wasi:logging/logging": crate::bindings::wasi::logging::logging,
180 }
181 });
182}
183
184#[cfg(feature = "export_golem_agentic")]
185pub use ctor;
186
187#[cfg(feature = "export_golem_agentic")]
188pub use async_trait;
189
190#[cfg(feature = "export_oplog_processor")]
191pub mod oplog_processor {
192 use wit_bindgen::generate;
193
194 generate!({
195 path: "wit",
196 world: "golem-rust-oplog-processor",
197 generate_all,
198 generate_unused_types: true,
199 pub_export_macro: true,
200 with: {
201 "golem:rpc/types@0.2.2": golem_wasm::golem_rpc_0_2_x::types,
202 "wasi:io/poll@0.2.3": wstd::wasi::io::poll,
203 "wasi:clocks/wall-clock@0.2.3": wstd::wasi::clocks::wall_clock,
204
205 "golem:api/host@1.3.0": crate::bindings::golem::api::host,
206 "golem:api/oplog@1.3.0": crate::bindings::golem::api::oplog,
207 "golem:api/context@1.3.0": crate::bindings::golem::api::context,
208 "golem:durability/durability@1.3.0": crate::bindings::golem::durability::durability,
209 "golem:rdbms/mysql@0.0.1": crate::bindings::golem::rdbms::mysql,
210 "golem:rdbms/postgres@0.0.1": crate::bindings::golem::rdbms::postgres,
211 "golem:rdbms/types@0.0.1": crate::bindings::golem::rdbms::types,
212 "wasi:blobstore/blobstore": crate::bindings::wasi::blobstore::blobstore,
213 "wasi:blobstore/container": crate::bindings::wasi::blobstore::container,
214 "wasi:blobstore/types": crate::bindings::wasi::blobstore::types,
215 "wasi:keyvalue/eventual-batch@0.1.0": crate::bindings::wasi::keyvalue::eventual_batch,
216 "wasi:keyvalue/eventual@0.1.0": crate::bindings::wasi::keyvalue::eventual,
217 "wasi:keyvalue/types@0.1.0": crate::bindings::wasi::keyvalue::types,
218 "wasi:keyvalue/wasi-keyvalue-error@0.1.0": crate::bindings::wasi::keyvalue::wasi_keyvalue_error,
219 "wasi:logging/logging": crate::bindings::wasi::logging::logging,
220 }
221 });
222
223 pub use __export_golem_rust_oplog_processor_impl as export_oplog_processor;
224}
225
226#[cfg(feature = "export_golem_agentic")]
227pub mod agentic;
228
229#[cfg(feature = "durability")]
230pub mod durability;
231
232#[cfg(feature = "json")]
233mod json;
234
235#[cfg(feature = "json")]
236pub use json::*;
237
238mod transaction;
239pub mod value_and_type;
240
241use bindings::golem::api::host::*;
242
243pub use golem_wasm;
244
245pub use bindings::golem::api::host::{
246 complete_promise, create_promise, fork, get_promise, oplog_commit,
247};
248pub use bindings::golem::api::host::{ForkResult, PersistenceLevel, PromiseId};
249
250pub use transaction::*;
251
252#[cfg(feature = "macro")]
253pub use golem_rust_macro::*;
254
255impl Display for PromiseId {
256 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
257 write!(f, "{}/{}", self.agent_id, self.oplog_idx)
258 }
259}
260
261impl FromStr for PromiseId {
262 type Err = String;
263
264 fn from_str(s: &str) -> Result<Self, Self::Err> {
265 let parts: Vec<&str> = s.split('/').collect();
266 if parts.len() == 2 {
267 let agent_id = AgentId::from_str(parts[0]).map_err(|_| {
268 format!("invalid agent id: {s} - expected format: <component_id>/<agent_id>")
269 })?;
270 let oplog_idx = parts[1]
271 .parse()
272 .map_err(|_| format!("invalid oplog index: {s} - expected integer"))?;
273 Ok(Self {
274 agent_id,
275 oplog_idx,
276 })
277 } else {
278 Err(format!(
279 "invalid promise id: {s} - expected format: <agent_id>/<oplog_idx>"
280 ))
281 }
282 }
283}
284
285pub fn blocking_await_promise(promise_id: &PromiseId) -> Vec<u8> {
291 let promise = get_promise(promise_id);
292 let pollable = promise.subscribe();
293 pollable.block();
294 promise.get().unwrap()
295}
296
297pub async fn await_promise(promise_id: &PromiseId) -> Vec<u8> {
302 let promise = get_promise(promise_id);
303 let pollable = promise.subscribe();
304 wstd::io::AsyncPollable::new(pollable).wait_for().await;
305 promise.get().unwrap()
306}
307
308#[derive(Clone, Debug, PartialEq)]
309pub struct RetryPolicy {
310 pub max_attempts: u32,
311 pub min_delay: std::time::Duration,
312 pub max_delay: std::time::Duration,
313 pub multiplier: f64,
314 pub max_jitter_factor: Option<f64>,
315}
316
317impl From<bindings::golem::api::host::RetryPolicy> for RetryPolicy {
318 fn from(value: bindings::golem::api::host::RetryPolicy) -> Self {
319 Self {
320 max_attempts: value.max_attempts,
321 min_delay: std::time::Duration::from_nanos(value.min_delay),
322 max_delay: std::time::Duration::from_nanos(value.max_delay),
323 multiplier: value.multiplier,
324 max_jitter_factor: value.max_jitter_factor,
325 }
326 }
327}
328
329impl From<RetryPolicy> for bindings::golem::api::host::RetryPolicy {
330 fn from(val: RetryPolicy) -> Self {
331 bindings::golem::api::host::RetryPolicy {
332 max_attempts: val.max_attempts,
333 min_delay: val.min_delay.as_nanos() as u64,
334 max_delay: val.max_delay.as_nanos() as u64,
335 multiplier: val.multiplier,
336 max_jitter_factor: val.max_jitter_factor,
337 }
338 }
339}
340
341pub struct PersistenceLevelGuard {
342 original_level: PersistenceLevel,
343}
344
345impl Drop for PersistenceLevelGuard {
346 fn drop(&mut self) {
347 set_oplog_persistence_level(self.original_level);
348 }
349}
350
351#[must_use]
355pub fn use_persistence_level(level: PersistenceLevel) -> PersistenceLevelGuard {
356 let original_level = get_oplog_persistence_level();
357 set_oplog_persistence_level(level);
358 PersistenceLevelGuard { original_level }
359}
360
361pub fn with_persistence_level<R>(level: PersistenceLevel, f: impl FnOnce() -> R) -> R {
363 let _guard = use_persistence_level(level);
364 f()
365}
366
367pub struct IdempotenceModeGuard {
368 original: bool,
369}
370
371impl Drop for IdempotenceModeGuard {
372 fn drop(&mut self) {
373 set_idempotence_mode(self.original);
374 }
375}
376
377#[must_use]
381pub fn use_idempotence_mode(mode: bool) -> IdempotenceModeGuard {
382 let original = get_idempotence_mode();
383 set_idempotence_mode(mode);
384 IdempotenceModeGuard { original }
385}
386
387pub fn with_idempotence_mode<R>(mode: bool, f: impl FnOnce() -> R) -> R {
389 let _guard = use_idempotence_mode(mode);
390 f()
391}
392
393pub fn generate_idempotency_key() -> uuid::Uuid {
397 Into::into(bindings::golem::api::host::generate_idempotency_key())
398}
399
400pub struct RetryPolicyGuard {
401 original: RetryPolicy,
402}
403
404impl Drop for RetryPolicyGuard {
405 fn drop(&mut self) {
406 set_retry_policy(Into::into(self.original.clone()));
407 }
408}
409
410#[must_use]
414pub fn use_retry_policy(policy: RetryPolicy) -> RetryPolicyGuard {
415 let original = Into::into(get_retry_policy());
416 set_retry_policy(Into::into(policy));
417 RetryPolicyGuard { original }
418}
419
420pub fn with_retry_policy<R>(policy: RetryPolicy, f: impl FnOnce() -> R) -> R {
422 let _guard = use_retry_policy(policy);
423 f()
424}
425
426pub struct AtomicOperationGuard {
427 begin: OplogIndex,
428}
429
430impl Drop for AtomicOperationGuard {
431 fn drop(&mut self) {
432 mark_end_operation(self.begin);
433 }
434}
435
436#[must_use]
441pub fn mark_atomic_operation() -> AtomicOperationGuard {
442 let begin = mark_begin_operation();
443 AtomicOperationGuard { begin }
444}
445
446pub fn atomically<T>(f: impl FnOnce() -> T) -> T {
450 let _guard = mark_atomic_operation();
451 f()
452}