1#![forbid(unsafe_code)]
2use std::{
6 future::Future,
7 pin::Pin,
8 sync::{
9 atomic::{AtomicBool, Ordering},
10 Arc,
11 },
12};
13
14use futures_core::Stream;
15use tokio::sync::Notify;
16
17mod builder;
18mod client;
19mod error;
20mod run_json;
21
22pub use builder::OpencodeClientBuilder;
23pub use client::OpencodeClient;
24pub use error::OpencodeError;
25pub use run_json::{
26 parse_run_json_lines, OpencodeRunCompletion, OpencodeRunJsonErrorCode, OpencodeRunJsonEvent,
27 OpencodeRunJsonLine, OpencodeRunJsonLineOutcome, OpencodeRunJsonParseError,
28 OpencodeRunJsonParser, OpencodeRunRequest,
29};
30
31pub type DynOpencodeRunJsonEventStream =
32 Pin<Box<dyn Stream<Item = Result<OpencodeRunJsonEvent, OpencodeRunJsonParseError>> + Send>>;
33
34pub type DynOpencodeRunJsonCompletion =
35 Pin<Box<dyn Future<Output = Result<OpencodeRunCompletion, OpencodeError>> + Send>>;
36
37#[derive(Clone)]
38pub struct OpencodeTerminationHandle {
39 inner: Arc<OpencodeTerminationInner>,
40}
41
42#[derive(Debug)]
43struct OpencodeTerminationInner {
44 requested: AtomicBool,
45 notify: Notify,
46}
47
48impl OpencodeTerminationHandle {
49 fn new() -> Self {
50 Self {
51 inner: Arc::new(OpencodeTerminationInner {
52 requested: AtomicBool::new(false),
53 notify: Notify::new(),
54 }),
55 }
56 }
57
58 pub fn request_termination(&self) {
59 if !self.inner.requested.swap(true, Ordering::SeqCst) {
60 self.inner.notify.notify_waiters();
61 }
62 }
63
64 fn is_requested(&self) -> bool {
65 self.inner.requested.load(Ordering::SeqCst)
66 }
67
68 async fn requested(&self) {
69 if self.is_requested() {
70 return;
71 }
72
73 let notified = self.inner.notify.notified();
74 if self.is_requested() {
75 return;
76 }
77
78 notified.await;
79 }
80}
81
82impl std::fmt::Debug for OpencodeTerminationHandle {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 f.debug_struct("OpencodeTerminationHandle")
85 .field("requested", &self.is_requested())
86 .finish()
87 }
88}
89
90pub struct OpencodeRunJsonHandle {
91 pub events: DynOpencodeRunJsonEventStream,
92 pub completion: DynOpencodeRunJsonCompletion,
93}
94
95impl std::fmt::Debug for OpencodeRunJsonHandle {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 f.debug_struct("OpencodeRunJsonHandle")
98 .field("events", &"<stream>")
99 .field("completion", &"<future>")
100 .finish()
101 }
102}
103
104pub struct OpencodeRunJsonControlHandle {
105 pub events: DynOpencodeRunJsonEventStream,
106 pub completion: DynOpencodeRunJsonCompletion,
107 pub termination: OpencodeTerminationHandle,
108}
109
110impl std::fmt::Debug for OpencodeRunJsonControlHandle {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 f.debug_struct("OpencodeRunJsonControlHandle")
113 .field("events", &"<stream>")
114 .field("completion", &"<future>")
115 .field("termination", &self.termination)
116 .finish()
117 }
118}