1mod evaluated_call;
13mod plugin_custom_value;
14mod protocol_info;
15
16#[cfg(test)]
17mod tests;
18
19#[doc(hidden)]
22pub mod test_util;
23
24use nu_protocol::{
25 ByteStreamType, Config, DeclId, LabeledError, PipelineData, PipelineMetadata, PluginMetadata,
26 PluginSignature, ShellError, SignalAction, Span, Spanned, Value, ast::Operator,
27 engine::Closure,
28};
29use nu_utils::SharedCow;
30use serde::{Deserialize, Serialize};
31use std::collections::HashMap;
32
33pub use evaluated_call::EvaluatedCall;
34pub use plugin_custom_value::PluginCustomValue;
35#[allow(unused_imports)] pub use protocol_info::{Feature, Protocol, ProtocolInfo};
37
38pub type StreamId = usize;
40
41pub type PluginCallId = usize;
43
44pub type EngineCallId = usize;
46
47#[derive(Serialize, Deserialize, Debug, Clone)]
51pub struct CallInfo<D> {
52 pub name: String,
54 pub call: EvaluatedCall,
56 pub input: D,
58}
59
60impl<D> CallInfo<D> {
61 pub fn map_data<T>(
63 self,
64 f: impl FnOnce(D) -> Result<T, ShellError>,
65 ) -> Result<CallInfo<T>, ShellError> {
66 Ok(CallInfo {
67 name: self.name,
68 call: self.call,
69 input: f(self.input)?,
70 })
71 }
72}
73
74#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
78pub enum PipelineDataHeader {
79 Empty,
81 Value(Value, Option<PipelineMetadata>),
83 ListStream(ListStreamInfo),
87 ByteStream(ByteStreamInfo),
91}
92
93impl PipelineDataHeader {
94 pub fn stream_id(&self) -> Option<StreamId> {
96 match self {
97 PipelineDataHeader::Empty => None,
98 PipelineDataHeader::Value(_, _) => None,
99 PipelineDataHeader::ListStream(info) => Some(info.id),
100 PipelineDataHeader::ByteStream(info) => Some(info.id),
101 }
102 }
103
104 pub fn value(value: Value) -> Self {
105 PipelineDataHeader::Value(value, None)
106 }
107
108 pub fn list_stream(info: ListStreamInfo) -> Self {
109 PipelineDataHeader::ListStream(info)
110 }
111
112 pub fn byte_stream(info: ByteStreamInfo) -> Self {
113 PipelineDataHeader::ByteStream(info)
114 }
115}
116
117#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
119pub struct ListStreamInfo {
120 pub id: StreamId,
121 pub span: Span,
122 pub metadata: Option<PipelineMetadata>,
123}
124
125impl ListStreamInfo {
126 pub fn new(id: StreamId, span: Span) -> Self {
128 ListStreamInfo {
129 id,
130 span,
131 metadata: None,
132 }
133 }
134}
135
136#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
138pub struct ByteStreamInfo {
139 pub id: StreamId,
140 pub span: Span,
141 #[serde(rename = "type")]
142 pub type_: ByteStreamType,
143 pub metadata: Option<PipelineMetadata>,
144}
145
146impl ByteStreamInfo {
147 pub fn new(id: StreamId, span: Span, type_: ByteStreamType) -> Self {
149 ByteStreamInfo {
150 id,
151 span,
152 type_,
153 metadata: None,
154 }
155 }
156}
157
158#[derive(Serialize, Deserialize, Debug, Clone)]
160pub enum PluginCall<D> {
161 Metadata,
162 Signature,
163 Run(CallInfo<D>),
164 CustomValueOp(Spanned<PluginCustomValue>, CustomValueOp),
165}
166
167impl<D> PluginCall<D> {
168 pub fn map_data<T>(
171 self,
172 f: impl FnOnce(D) -> Result<T, ShellError>,
173 ) -> Result<PluginCall<T>, ShellError> {
174 Ok(match self {
175 PluginCall::Metadata => PluginCall::Metadata,
176 PluginCall::Signature => PluginCall::Signature,
177 PluginCall::Run(call) => PluginCall::Run(call.map_data(f)?),
178 PluginCall::CustomValueOp(custom_value, op) => {
179 PluginCall::CustomValueOp(custom_value, op)
180 }
181 })
182 }
183
184 pub fn span(&self) -> Option<Span> {
186 match self {
187 PluginCall::Metadata => None,
188 PluginCall::Signature => None,
189 PluginCall::Run(CallInfo { call, .. }) => Some(call.head),
190 PluginCall::CustomValueOp(val, _) => Some(val.span),
191 }
192 }
193}
194
195#[derive(Serialize, Deserialize, Debug, Clone)]
197pub enum CustomValueOp {
198 ToBaseValue,
200 FollowPathInt(Spanned<usize>),
202 FollowPathString(Spanned<String>),
204 PartialCmp(Value),
206 Operation(Spanned<Operator>, Value),
208 Dropped,
211}
212
213impl CustomValueOp {
214 pub fn name(&self) -> &'static str {
216 match self {
217 CustomValueOp::ToBaseValue => "to_base_value",
218 CustomValueOp::FollowPathInt(_) => "follow_path_int",
219 CustomValueOp::FollowPathString(_) => "follow_path_string",
220 CustomValueOp::PartialCmp(_) => "partial_cmp",
221 CustomValueOp::Operation(_, _) => "operation",
222 CustomValueOp::Dropped => "dropped",
223 }
224 }
225}
226
227#[derive(Serialize, Deserialize, Debug, Clone)]
229pub enum PluginInput {
230 Hello(ProtocolInfo),
232 Call(PluginCallId, PluginCall<PipelineDataHeader>),
235 Goodbye,
238 EngineCallResponse(EngineCallId, EngineCallResponse<PipelineDataHeader>),
241 Data(StreamId, StreamData),
243 End(StreamId),
245 Drop(StreamId),
247 Ack(StreamId),
249 Signal(SignalAction),
251}
252
253impl TryFrom<PluginInput> for StreamMessage {
254 type Error = PluginInput;
255
256 fn try_from(msg: PluginInput) -> Result<StreamMessage, PluginInput> {
257 match msg {
258 PluginInput::Data(id, data) => Ok(StreamMessage::Data(id, data)),
259 PluginInput::End(id) => Ok(StreamMessage::End(id)),
260 PluginInput::Drop(id) => Ok(StreamMessage::Drop(id)),
261 PluginInput::Ack(id) => Ok(StreamMessage::Ack(id)),
262 _ => Err(msg),
263 }
264 }
265}
266
267impl From<StreamMessage> for PluginInput {
268 fn from(stream_msg: StreamMessage) -> PluginInput {
269 match stream_msg {
270 StreamMessage::Data(id, data) => PluginInput::Data(id, data),
271 StreamMessage::End(id) => PluginInput::End(id),
272 StreamMessage::Drop(id) => PluginInput::Drop(id),
273 StreamMessage::Ack(id) => PluginInput::Ack(id),
274 }
275 }
276}
277
278#[derive(Serialize, Deserialize, Debug, Clone)]
280pub enum StreamData {
281 List(Value),
282 Raw(Result<Vec<u8>, LabeledError>),
283}
284
285impl From<Value> for StreamData {
286 fn from(value: Value) -> Self {
287 StreamData::List(value)
288 }
289}
290
291impl From<Result<Vec<u8>, LabeledError>> for StreamData {
292 fn from(value: Result<Vec<u8>, LabeledError>) -> Self {
293 StreamData::Raw(value)
294 }
295}
296
297impl From<Result<Vec<u8>, ShellError>> for StreamData {
298 fn from(value: Result<Vec<u8>, ShellError>) -> Self {
299 value.map_err(LabeledError::from).into()
300 }
301}
302
303impl TryFrom<StreamData> for Value {
304 type Error = ShellError;
305
306 fn try_from(data: StreamData) -> Result<Value, ShellError> {
307 match data {
308 StreamData::List(value) => Ok(value),
309 StreamData::Raw(_) => Err(ShellError::PluginFailedToDecode {
310 msg: "expected list stream data, found raw data".into(),
311 }),
312 }
313 }
314}
315
316impl TryFrom<StreamData> for Result<Vec<u8>, LabeledError> {
317 type Error = ShellError;
318
319 fn try_from(data: StreamData) -> Result<Result<Vec<u8>, LabeledError>, ShellError> {
320 match data {
321 StreamData::Raw(value) => Ok(value),
322 StreamData::List(_) => Err(ShellError::PluginFailedToDecode {
323 msg: "expected raw stream data, found list data".into(),
324 }),
325 }
326 }
327}
328
329impl TryFrom<StreamData> for Result<Vec<u8>, ShellError> {
330 type Error = ShellError;
331
332 fn try_from(value: StreamData) -> Result<Result<Vec<u8>, ShellError>, ShellError> {
333 Result::<Vec<u8>, LabeledError>::try_from(value).map(|res| res.map_err(ShellError::from))
334 }
335}
336
337#[derive(Serialize, Deserialize, Debug, Clone)]
339pub enum StreamMessage {
340 Data(StreamId, StreamData),
342 End(StreamId),
344 Drop(StreamId),
347 Ack(StreamId),
350}
351
352#[derive(Serialize, Deserialize, Debug, Clone)]
354pub enum PluginCallResponse<D> {
355 Error(LabeledError),
356 Metadata(PluginMetadata),
357 Signature(Vec<PluginSignature>),
358 Ordering(Option<Ordering>),
359 PipelineData(D),
360}
361
362impl<D> PluginCallResponse<D> {
363 pub fn map_data<T>(
366 self,
367 f: impl FnOnce(D) -> Result<T, ShellError>,
368 ) -> Result<PluginCallResponse<T>, ShellError> {
369 Ok(match self {
370 PluginCallResponse::Error(err) => PluginCallResponse::Error(err),
371 PluginCallResponse::Metadata(meta) => PluginCallResponse::Metadata(meta),
372 PluginCallResponse::Signature(sigs) => PluginCallResponse::Signature(sigs),
373 PluginCallResponse::Ordering(ordering) => PluginCallResponse::Ordering(ordering),
374 PluginCallResponse::PipelineData(input) => PluginCallResponse::PipelineData(f(input)?),
375 })
376 }
377}
378
379impl PluginCallResponse<PipelineDataHeader> {
380 pub fn value(value: Value) -> PluginCallResponse<PipelineDataHeader> {
382 if value.is_nothing() {
383 PluginCallResponse::PipelineData(PipelineDataHeader::Empty)
384 } else {
385 PluginCallResponse::PipelineData(PipelineDataHeader::value(value))
386 }
387 }
388}
389
390impl PluginCallResponse<PipelineData> {
391 pub fn has_stream(&self) -> bool {
393 match self {
394 PluginCallResponse::PipelineData(data) => match data {
395 PipelineData::Empty => false,
396 PipelineData::Value(..) => false,
397 PipelineData::ListStream(..) => true,
398 PipelineData::ByteStream(..) => true,
399 },
400 _ => false,
401 }
402 }
403}
404
405#[derive(Serialize, Deserialize, Debug, Clone)]
407pub enum PluginOption {
408 GcDisabled(bool),
413}
414
415#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
417pub enum Ordering {
418 Less,
419 Equal,
420 Greater,
421}
422
423impl From<std::cmp::Ordering> for Ordering {
424 fn from(value: std::cmp::Ordering) -> Self {
425 match value {
426 std::cmp::Ordering::Less => Ordering::Less,
427 std::cmp::Ordering::Equal => Ordering::Equal,
428 std::cmp::Ordering::Greater => Ordering::Greater,
429 }
430 }
431}
432
433impl From<Ordering> for std::cmp::Ordering {
434 fn from(value: Ordering) -> Self {
435 match value {
436 Ordering::Less => std::cmp::Ordering::Less,
437 Ordering::Equal => std::cmp::Ordering::Equal,
438 Ordering::Greater => std::cmp::Ordering::Greater,
439 }
440 }
441}
442
443#[derive(Serialize, Deserialize, Debug, Clone)]
445pub enum PluginOutput {
446 Hello(ProtocolInfo),
448 Option(PluginOption),
450 CallResponse(PluginCallId, PluginCallResponse<PipelineDataHeader>),
453 EngineCall {
456 context: PluginCallId,
458 id: EngineCallId,
460 call: EngineCall<PipelineDataHeader>,
461 },
462 Data(StreamId, StreamData),
464 End(StreamId),
466 Drop(StreamId),
468 Ack(StreamId),
470}
471
472impl TryFrom<PluginOutput> for StreamMessage {
473 type Error = PluginOutput;
474
475 fn try_from(msg: PluginOutput) -> Result<StreamMessage, PluginOutput> {
476 match msg {
477 PluginOutput::Data(id, data) => Ok(StreamMessage::Data(id, data)),
478 PluginOutput::End(id) => Ok(StreamMessage::End(id)),
479 PluginOutput::Drop(id) => Ok(StreamMessage::Drop(id)),
480 PluginOutput::Ack(id) => Ok(StreamMessage::Ack(id)),
481 _ => Err(msg),
482 }
483 }
484}
485
486impl From<StreamMessage> for PluginOutput {
487 fn from(stream_msg: StreamMessage) -> PluginOutput {
488 match stream_msg {
489 StreamMessage::Data(id, data) => PluginOutput::Data(id, data),
490 StreamMessage::End(id) => PluginOutput::End(id),
491 StreamMessage::Drop(id) => PluginOutput::Drop(id),
492 StreamMessage::Ack(id) => PluginOutput::Ack(id),
493 }
494 }
495}
496
497#[derive(Serialize, Deserialize, Debug, Clone)]
501pub enum EngineCall<D> {
502 GetConfig,
504 GetPluginConfig,
506 GetEnvVar(String),
508 GetEnvVars,
510 GetCurrentDir,
512 AddEnvVar(String, Value),
514 GetHelp,
516 EnterForeground,
518 LeaveForeground,
520 GetSpanContents(Span),
522 EvalClosure {
524 closure: Spanned<Closure>,
528 positional: Vec<Value>,
530 input: D,
532 redirect_stdout: bool,
534 redirect_stderr: bool,
536 },
537 FindDecl(String),
539 CallDecl {
541 decl_id: DeclId,
543 call: EvaluatedCall,
545 input: D,
547 redirect_stdout: bool,
549 redirect_stderr: bool,
551 },
552}
553
554impl<D> EngineCall<D> {
555 pub fn name(&self) -> &'static str {
557 match self {
558 EngineCall::GetConfig => "GetConfig",
559 EngineCall::GetPluginConfig => "GetPluginConfig",
560 EngineCall::GetEnvVar(_) => "GetEnv",
561 EngineCall::GetEnvVars => "GetEnvs",
562 EngineCall::GetCurrentDir => "GetCurrentDir",
563 EngineCall::AddEnvVar(..) => "AddEnvVar",
564 EngineCall::GetHelp => "GetHelp",
565 EngineCall::EnterForeground => "EnterForeground",
566 EngineCall::LeaveForeground => "LeaveForeground",
567 EngineCall::GetSpanContents(_) => "GetSpanContents",
568 EngineCall::EvalClosure { .. } => "EvalClosure",
569 EngineCall::FindDecl(_) => "FindDecl",
570 EngineCall::CallDecl { .. } => "CallDecl",
571 }
572 }
573
574 pub fn map_data<T>(
577 self,
578 f: impl FnOnce(D) -> Result<T, ShellError>,
579 ) -> Result<EngineCall<T>, ShellError> {
580 Ok(match self {
581 EngineCall::GetConfig => EngineCall::GetConfig,
582 EngineCall::GetPluginConfig => EngineCall::GetPluginConfig,
583 EngineCall::GetEnvVar(name) => EngineCall::GetEnvVar(name),
584 EngineCall::GetEnvVars => EngineCall::GetEnvVars,
585 EngineCall::GetCurrentDir => EngineCall::GetCurrentDir,
586 EngineCall::AddEnvVar(name, value) => EngineCall::AddEnvVar(name, value),
587 EngineCall::GetHelp => EngineCall::GetHelp,
588 EngineCall::EnterForeground => EngineCall::EnterForeground,
589 EngineCall::LeaveForeground => EngineCall::LeaveForeground,
590 EngineCall::GetSpanContents(span) => EngineCall::GetSpanContents(span),
591 EngineCall::EvalClosure {
592 closure,
593 positional,
594 input,
595 redirect_stdout,
596 redirect_stderr,
597 } => EngineCall::EvalClosure {
598 closure,
599 positional,
600 input: f(input)?,
601 redirect_stdout,
602 redirect_stderr,
603 },
604 EngineCall::FindDecl(name) => EngineCall::FindDecl(name),
605 EngineCall::CallDecl {
606 decl_id,
607 call,
608 input,
609 redirect_stdout,
610 redirect_stderr,
611 } => EngineCall::CallDecl {
612 decl_id,
613 call,
614 input: f(input)?,
615 redirect_stdout,
616 redirect_stderr,
617 },
618 })
619 }
620}
621
622#[derive(Serialize, Deserialize, Debug, Clone)]
625pub enum EngineCallResponse<D> {
626 Error(ShellError),
627 PipelineData(D),
628 Config(SharedCow<Config>),
629 ValueMap(HashMap<String, Value>),
630 Identifier(DeclId),
631}
632
633impl<D> EngineCallResponse<D> {
634 pub fn map_data<T>(
637 self,
638 f: impl FnOnce(D) -> Result<T, ShellError>,
639 ) -> Result<EngineCallResponse<T>, ShellError> {
640 Ok(match self {
641 EngineCallResponse::Error(err) => EngineCallResponse::Error(err),
642 EngineCallResponse::PipelineData(data) => EngineCallResponse::PipelineData(f(data)?),
643 EngineCallResponse::Config(config) => EngineCallResponse::Config(config),
644 EngineCallResponse::ValueMap(map) => EngineCallResponse::ValueMap(map),
645 EngineCallResponse::Identifier(id) => EngineCallResponse::Identifier(id),
646 })
647 }
648}
649
650impl EngineCallResponse<PipelineData> {
651 pub fn value(value: Value) -> EngineCallResponse<PipelineData> {
653 EngineCallResponse::PipelineData(PipelineData::value(value, None))
654 }
655
656 pub const fn empty() -> EngineCallResponse<PipelineData> {
658 EngineCallResponse::PipelineData(PipelineData::empty())
659 }
660}