1use crate::schema::conversion::{FromSchema, FromSchemaError, IntoSchema, SchemaBuilder};
18use crate::schema::metadata::{MetadataEnvelope, TypeId};
19use crate::schema::schema_type::SchemaType;
20use crate::schema::schema_value::SchemaValue;
21
22#[cfg(all(feature = "guest", not(feature = "host")))]
23type RawSchemaValueStream = wit_bindgen::StreamReader<super::wit::wire::SchemaValueTree>;
24
25#[cfg(all(
26 any(feature = "host", feature = "native-stream"),
27 not(feature = "guest")
28))]
29mod active {
30 use std::any::Any;
31 use std::sync::{Arc, Mutex};
32
33 type OpaqueEndpoint = Box<dyn Any + Send>;
34
35 #[derive(Clone)]
42 pub struct SchemaValueStream {
43 inner: Arc<Mutex<Option<OpaqueEndpoint>>>,
44 }
45
46 impl SchemaValueStream {
47 #[doc(hidden)]
48 pub fn from_host_endpoint(endpoint: impl Any + Send) -> Self {
49 Self {
50 inner: Arc::new(Mutex::new(Some(Box::new(endpoint)))),
51 }
52 }
53
54 #[doc(hidden)]
55 pub fn take_host_endpoint<T: Any + Send>(&self) -> Result<T, String> {
56 let endpoint = self
57 .inner
58 .lock()
59 .expect("schema value stream mutex poisoned")
60 .take()
61 .ok_or_else(|| "schema value stream was already transferred".to_string())?;
62 endpoint
63 .downcast::<T>()
64 .map(|endpoint| *endpoint)
65 .map_err(|_| {
66 "schema value stream endpoint belongs to an incompatible runtime".to_string()
67 })
68 }
69
70 #[doc(hidden)]
71 pub fn with_host_endpoint<T: Any + Send, R>(
72 &self,
73 f: impl FnOnce(&T) -> R,
74 ) -> Result<R, String> {
75 let endpoint = self
76 .inner
77 .lock()
78 .expect("schema value stream mutex poisoned");
79 let endpoint = endpoint
80 .as_ref()
81 .ok_or_else(|| "schema value stream was already transferred".to_string())?;
82 endpoint.downcast_ref::<T>().map(f).ok_or_else(|| {
83 "schema value stream endpoint belongs to an incompatible runtime".to_string()
84 })
85 }
86
87 #[doc(hidden)]
88 pub fn take_for_transfer(&self) -> Option<Self> {
89 self.inner
90 .lock()
91 .expect("schema value stream mutex poisoned")
92 .take()
93 .map(|endpoint| Self {
94 inner: Arc::new(Mutex::new(Some(endpoint))),
95 })
96 }
97
98 #[doc(hidden)]
99 pub fn is_present(&self) -> bool {
100 self.inner
101 .lock()
102 .expect("schema value stream mutex poisoned")
103 .is_some()
104 }
105
106 #[doc(hidden)]
107 pub fn cell_id(&self) -> *const () {
108 Arc::as_ptr(&self.inner).cast()
109 }
110 }
111
112 impl std::fmt::Debug for SchemaValueStream {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 f.debug_tuple("SchemaValueStream")
115 .field(&if self.is_present() {
116 "present"
117 } else {
118 "consumed"
119 })
120 .finish()
121 }
122 }
123
124 impl PartialEq for SchemaValueStream {
125 fn eq(&self, other: &Self) -> bool {
126 Arc::ptr_eq(&self.inner, &other.inner)
127 }
128 }
129
130 #[cfg(feature = "host")]
135 pub struct SchemaValueStreamHandleRep {
136 stream: SchemaValueStream,
137 }
138
139 #[cfg(feature = "host")]
140 impl SchemaValueStreamHandleRep {
141 #[doc(hidden)]
142 pub fn new(stream: SchemaValueStream) -> Self {
143 Self { stream }
144 }
145
146 #[doc(hidden)]
147 pub fn into_stream(self) -> SchemaValueStream {
148 self.stream
149 }
150 }
151}
152
153#[cfg(all(feature = "guest", not(feature = "host")))]
154mod active {
155 use super::RawSchemaValueStream;
156 use crate::schema::wit::wire;
157 use std::future::Future;
158 use std::pin::Pin;
159 use std::sync::{Arc, Mutex, MutexGuard};
160
161 pub trait SchemaValueStreamSource: Send {
164 fn next(
165 &mut self,
166 ) -> Pin<Box<dyn Future<Output = Result<Option<wire::SchemaValueTree>, String>> + Send + '_>>;
167 }
168
169 enum State {
170 Wrapped(wire::SchemaValueStream),
171 Native(RawSchemaValueStream),
172 Source(Box<dyn SchemaValueStreamSource>),
173 }
174
175 fn source_reader(mut source: Box<dyn SchemaValueStreamSource>) -> RawSchemaValueStream {
176 let (mut writer, reader) = crate::schema::wit::new_schema_value_stream();
177 wit_bindgen::spawn_local(async move {
178 loop {
179 match source.next().await {
180 Ok(Some(item)) => {
181 if writer.write_one(item).await.is_some() {
182 break;
183 }
184 }
185 Ok(None) => break,
186 Err(error) => panic!("agent stream producer failed: {error}"),
187 }
188 }
189 });
190 reader
191 }
192
193 #[derive(Clone)]
196 pub struct SchemaValueStream {
197 inner: Arc<Mutex<Option<State>>>,
198 }
199
200 impl SchemaValueStream {
201 fn state(&self) -> MutexGuard<'_, Option<State>> {
202 self.inner
203 .lock()
204 .unwrap_or_else(|poison| poison.into_inner())
205 }
206
207 pub fn from_source(source: impl SchemaValueStreamSource + 'static) -> Self {
209 Self {
210 inner: Arc::new(Mutex::new(Some(State::Source(Box::new(source))))),
211 }
212 }
213
214 #[doc(hidden)]
215 pub fn from_native(reader: RawSchemaValueStream) -> Self {
216 Self {
217 inner: Arc::new(Mutex::new(Some(State::Native(reader)))),
218 }
219 }
220
221 #[doc(hidden)]
222 pub fn from_wrapped(stream: wire::SchemaValueStream) -> Self {
223 Self {
224 inner: Arc::new(Mutex::new(Some(State::Wrapped(stream)))),
225 }
226 }
227
228 #[doc(hidden)]
229 pub fn is_present(&self) -> bool {
230 self.state().is_some()
231 }
232
233 #[doc(hidden)]
234 pub fn is_wrapped(&self) -> bool {
235 matches!(&*self.state(), Some(State::Wrapped(_)))
236 }
237
238 #[doc(hidden)]
239 pub fn cell_id(&self) -> *const () {
240 Arc::as_ptr(&self.inner).cast()
241 }
242
243 #[doc(hidden)]
244 pub fn take_wrapped(&self) -> Option<wire::SchemaValueStream> {
245 let mut state = self.state();
246 match state.take() {
247 Some(State::Wrapped(stream)) => Some(stream),
248 Some(native @ (State::Native(_) | State::Source(_))) => {
249 *state = Some(native);
250 None
251 }
252 None => None,
253 }
254 }
255
256 #[doc(hidden)]
257 pub async fn take_wrapped_async(&self) -> Result<wire::SchemaValueStream, String> {
258 let state = self
259 .state()
260 .take()
261 .ok_or_else(|| "schema value stream was already transferred".to_string())?;
262 Ok(match state {
263 State::Wrapped(stream) => stream,
264 State::Native(reader) => wire::SchemaValueStream::wrap(reader).await,
265 State::Source(source) => wire::SchemaValueStream::wrap(source_reader(source)).await,
266 })
267 }
268
269 #[doc(hidden)]
270 pub async fn ensure_wrapped(&self) -> Result<(), String> {
271 let state = self
272 .state()
273 .take()
274 .ok_or_else(|| "schema value stream was already transferred".to_string())?;
275 *self.state() = Some(match state {
276 State::Wrapped(stream) => State::Wrapped(stream),
277 State::Native(reader) => {
278 State::Wrapped(wire::SchemaValueStream::wrap(reader).await)
279 }
280 State::Source(source) => {
281 State::Wrapped(wire::SchemaValueStream::wrap(source_reader(source)).await)
282 }
283 });
284 Ok(())
285 }
286
287 #[doc(hidden)]
288 pub async fn take_native(self) -> Result<RawSchemaValueStream, String> {
289 let state = self
290 .state()
291 .take()
292 .ok_or_else(|| "schema value stream was already transferred".to_string())?;
293 Ok(match state {
294 State::Wrapped(stream) => wire::SchemaValueStream::unwrap(stream).await,
295 State::Native(reader) => reader,
296 State::Source(source) => source_reader(source),
297 })
298 }
299
300 #[doc(hidden)]
301 pub async fn next_wire(&self) -> Result<Option<wire::SchemaValueTree>, String> {
302 let state = self.state().take().ok_or_else(|| {
303 "schema value stream is already in use or was transferred".to_string()
304 })?;
305 if let State::Source(source) = state {
306 struct Restore<'a> {
308 stream: &'a SchemaValueStream,
309 source: Option<Box<dyn SchemaValueStreamSource>>,
310 }
311 impl Drop for Restore<'_> {
312 fn drop(&mut self) {
313 *self.stream.state() = self.source.take().map(State::Source);
314 }
315 }
316 let mut restore = Restore {
317 stream: self,
318 source: Some(source),
319 };
320 return restore.source.as_mut().unwrap().next().await;
321 }
322 let mut reader = match state {
323 State::Wrapped(stream) => wire::SchemaValueStream::unwrap(stream).await,
324 State::Native(reader) => reader,
325 State::Source(_) => unreachable!(),
326 };
327 let item = reader.next().await;
328 *self.state() = Some(State::Native(reader));
329 Ok(item)
330 }
331 }
332
333 impl std::fmt::Debug for SchemaValueStream {
334 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
335 let state = match &*self.state() {
336 Some(State::Wrapped(_)) => "wrapped",
337 Some(State::Native(_)) => "native",
338 Some(State::Source(_)) => "source",
339 None => "consumed",
340 };
341 f.debug_tuple("SchemaValueStream").field(&state).finish()
342 }
343 }
344
345 impl PartialEq for SchemaValueStream {
346 fn eq(&self, other: &Self) -> bool {
347 Arc::ptr_eq(&self.inner, &other.inner)
348 }
349 }
350}
351
352#[cfg(any(
353 all(
354 any(feature = "host", feature = "native-stream"),
355 not(feature = "guest")
356 ),
357 all(feature = "guest", not(feature = "host"))
358))]
359pub use active::SchemaValueStream;
360
361#[cfg(all(feature = "guest", not(feature = "host")))]
362pub use active::SchemaValueStreamSource;
363
364#[cfg(all(feature = "host", not(feature = "guest")))]
365pub use active::SchemaValueStreamHandleRep;
366
367#[cfg(not(any(
368 all(
369 any(feature = "host", feature = "native-stream"),
370 not(feature = "guest")
371 ),
372 all(feature = "guest", not(feature = "host"))
373)))]
374#[derive(Clone, Debug, PartialEq)]
375pub struct SchemaValueStream(());
376
377impl serde::Serialize for SchemaValueStream {
378 fn serialize<S: serde::Serializer>(&self, _serializer: S) -> Result<S::Ok, S::Error> {
379 Err(serde::ser::Error::custom(
380 "live schema value streams cannot be serialized",
381 ))
382 }
383}
384
385impl<'de> serde::Deserialize<'de> for SchemaValueStream {
386 fn deserialize<D: serde::Deserializer<'de>>(_deserializer: D) -> Result<Self, D::Error> {
387 Err(serde::de::Error::custom(
388 "live schema value streams cannot be deserialized",
389 ))
390 }
391}
392
393impl IntoSchema for SchemaValueStream {
394 fn type_id() -> TypeId {
395 TypeId::new("golem.core.SchemaValueStream")
396 }
397
398 fn register_in(_builder: &mut SchemaBuilder) -> SchemaType {
399 SchemaType::Stream {
400 inner: None,
401 metadata: MetadataEnvelope::default(),
402 }
403 }
404
405 fn to_value(&self) -> SchemaValue {
406 SchemaValue::Stream(self.clone())
407 }
408}
409
410impl FromSchema for SchemaValueStream {
411 fn from_value(value: &SchemaValue) -> Result<Self, FromSchemaError> {
412 match value {
413 SchemaValue::Stream(stream) => Ok(stream.clone()),
414 other => Err(FromSchemaError::shape_mismatch(
415 "stream",
416 format!("{other:?}"),
417 "SchemaValueStream",
418 )),
419 }
420 }
421}