1use crate::time;
51
52pub use crate::{
53    media::{Media, MediaType},
54    ExecutionCount,
55};
56
57use bytes::Bytes;
58use chrono::{DateTime, Utc};
59use serde::{Deserialize, Serialize};
60use serde_json::{json, Value};
61use std::{collections::HashMap, fmt};
62use uuid::Uuid;
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
89#[serde(rename_all = "lowercase")]
90pub enum Channel {
91    Shell,
93    Control,
95    Stdin,
97    IOPub,
99    Heartbeat,
101}
102
103#[derive(Serialize, Deserialize, Debug, Clone)]
104struct UnknownJupyterMessage {
105    pub header: Header,
106    pub parent_header: Option<Header>,
107    pub metadata: Value,
108    pub content: Value,
109    #[serde(skip_serializing, skip_deserializing)]
110    pub buffers: Vec<Bytes>,
111}
112
113#[derive(Serialize, Deserialize, Debug, Clone)]
142pub struct Header {
143    pub msg_id: String,
144    pub username: String,
145    pub session: String,
146    pub date: DateTime<Utc>,
147    pub msg_type: String,
148    pub version: String,
149}
150
151fn serialize_parent_header<S>(
159    parent_header: &Option<Header>,
160    serializer: S,
161) -> Result<S::Ok, S::Error>
162where
163    S: serde::Serializer,
164{
165    match parent_header {
166        Some(parent_header) => parent_header.serialize(serializer),
167        None => serde_json::Map::new().serialize(serializer),
168    }
169}
170
171#[derive(Deserialize, Serialize, Clone)]
220pub struct JupyterMessage {
221    #[serde(skip_serializing, skip_deserializing)]
222    pub zmq_identities: Vec<Bytes>,
223    pub header: Header,
224    #[serde(serialize_with = "serialize_parent_header")]
225    pub parent_header: Option<Header>,
226    pub metadata: Value,
227    pub content: JupyterMessageContent,
228    #[serde(skip_serializing, skip_deserializing)]
229    pub buffers: Vec<Bytes>,
230    pub channel: Option<Channel>,
231}
232
233impl JupyterMessage {
234    pub fn new(
235        content: impl Into<JupyterMessageContent>,
236        parent: Option<&JupyterMessage>,
237    ) -> JupyterMessage {
238        let session = match parent {
242            Some(parent) => parent.header.session.clone(),
243            None => Uuid::new_v4().to_string(),
244        };
245
246        let content = content.into();
247
248        let header = Header {
249            msg_id: Uuid::new_v4().to_string(),
250            username: "runtimelib".to_string(),
251            session,
252            date: time::utc_now(),
253            msg_type: content.message_type().to_owned(),
254            version: "5.3".to_string(),
255        };
256
257        JupyterMessage {
258            zmq_identities: parent.map_or(Vec::new(), |parent| parent.zmq_identities.clone()),
259            header,
260            parent_header: parent.map(|parent| parent.header.clone()),
261            metadata: json!({}),
262            content,
263            buffers: Vec::new(),
264            channel: None,
265        }
266    }
267
268    pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
269        self.metadata = metadata;
270        self
271    }
272
273    pub fn with_buffers(mut self, buffers: Vec<Bytes>) -> Self {
274        self.buffers = buffers;
275        self
276    }
277
278    pub fn with_parent(mut self, parent: &JupyterMessage) -> Self {
279        self.header.session.clone_from(&parent.header.session);
280        self.parent_header = Some(parent.header.clone());
281        self.zmq_identities.clone_from(&parent.zmq_identities);
282        self
283    }
284
285    pub fn with_zmq_identities(mut self, zmq_identities: Vec<Bytes>) -> Self {
286        self.zmq_identities = zmq_identities;
287        self
288    }
289
290    pub fn with_session(mut self, session: &str) -> Self {
291        self.header.session = session.to_string();
292        self
293    }
294
295    pub fn message_type(&self) -> &str {
296        self.content.message_type()
297    }
298
299    pub fn from_value(message: Value) -> Result<JupyterMessage, anyhow::Error> {
300        let message = serde_json::from_value::<UnknownJupyterMessage>(message)?;
301
302        let content =
303            JupyterMessageContent::from_type_and_content(&message.header.msg_type, message.content);
304
305        let content = match content {
306            Ok(content) => content,
307            Err(err) => {
308                return Err(anyhow::anyhow!(
309                    "Error deserializing content for msg_type `{}`: {}",
310                    &message.header.msg_type,
311                    err
312                ));
313            }
314        };
315
316        let message = JupyterMessage {
317            zmq_identities: Vec::new(),
318            header: message.header,
319            parent_header: message.parent_header,
320            metadata: message.metadata,
321            content,
322            buffers: message.buffers,
323            channel: None,
324        };
325
326        Ok(message)
327    }
328}
329
330impl fmt::Debug for JupyterMessage {
331    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
332        writeln!(
333            f,
334            "\nHeader: {}",
335            serde_json::to_string_pretty(&self.header).unwrap()
336        )?;
337        writeln!(
338            f,
339            "Parent header: {}",
340            if let Some(parent_header) = self.parent_header.as_ref() {
341                serde_json::to_string_pretty(parent_header).unwrap()
342            } else {
343                serde_json::to_string_pretty(&serde_json::Map::new()).unwrap()
344            }
345        )?;
346        writeln!(
347            f,
348            "Metadata: {}",
349            serde_json::to_string_pretty(&self.metadata).unwrap()
350        )?;
351        writeln!(
352            f,
353            "Content: {}\n",
354            serde_json::to_string_pretty(&self.content).unwrap()
355        )?;
356        Ok(())
357    }
358}
359
360#[derive(Serialize, Deserialize, Debug, Clone)]
361#[serde(untagged)]
362pub enum JupyterMessageContent {
363    ClearOutput(ClearOutput),
364    CommClose(CommClose),
365    CommInfoReply(CommInfoReply),
366    CommInfoRequest(CommInfoRequest),
367    CommMsg(CommMsg),
368    CommOpen(CommOpen),
369    CompleteReply(CompleteReply),
370    CompleteRequest(CompleteRequest),
371    DebugReply(DebugReply),
372    DebugRequest(DebugRequest),
373    DisplayData(DisplayData),
374    ErrorOutput(ErrorOutput),
375    ExecuteInput(ExecuteInput),
376    ExecuteReply(ExecuteReply),
377    ExecuteRequest(ExecuteRequest),
378    ExecuteResult(ExecuteResult),
379    HistoryReply(HistoryReply),
380    HistoryRequest(HistoryRequest),
381    InputReply(InputReply),
382    InputRequest(InputRequest),
383    InspectReply(InspectReply),
384    InspectRequest(InspectRequest),
385    InterruptReply(InterruptReply),
386    InterruptRequest(InterruptRequest),
387    IsCompleteReply(IsCompleteReply),
388    IsCompleteRequest(IsCompleteRequest),
389    KernelInfoReply(Box<KernelInfoReply>),
392    KernelInfoRequest(KernelInfoRequest),
393    ShutdownReply(ShutdownReply),
394    ShutdownRequest(ShutdownRequest),
395    Status(Status),
396    StreamContent(StreamContent),
397    UnknownMessage(UnknownMessage),
398    UpdateDisplayData(UpdateDisplayData),
399}
400
401impl JupyterMessageContent {
402    pub fn message_type(&self) -> &str {
403        match self {
404            JupyterMessageContent::ClearOutput(_) => "clear_output",
405            JupyterMessageContent::CommClose(_) => "comm_close",
406            JupyterMessageContent::CommInfoReply(_) => "comm_info_reply",
407            JupyterMessageContent::CommInfoRequest(_) => "comm_info_request",
408            JupyterMessageContent::CommMsg(_) => "comm_msg",
409            JupyterMessageContent::CommOpen(_) => "comm_open",
410            JupyterMessageContent::CompleteReply(_) => "complete_reply",
411            JupyterMessageContent::CompleteRequest(_) => "complete_request",
412            JupyterMessageContent::DebugReply(_) => "debug_reply",
413            JupyterMessageContent::DebugRequest(_) => "debug_request",
414            JupyterMessageContent::DisplayData(_) => "display_data",
415            JupyterMessageContent::ErrorOutput(_) => "error",
416            JupyterMessageContent::ExecuteInput(_) => "execute_input",
417            JupyterMessageContent::ExecuteReply(_) => "execute_reply",
418            JupyterMessageContent::ExecuteRequest(_) => "execute_request",
419            JupyterMessageContent::ExecuteResult(_) => "execute_result",
420            JupyterMessageContent::HistoryReply(_) => "history_reply",
421            JupyterMessageContent::HistoryRequest(_) => "history_request",
422            JupyterMessageContent::InputReply(_) => "input_reply",
423            JupyterMessageContent::InputRequest(_) => "input_request",
424            JupyterMessageContent::InspectReply(_) => "inspect_reply",
425            JupyterMessageContent::InspectRequest(_) => "inspect_request",
426            JupyterMessageContent::InterruptReply(_) => "interrupt_reply",
427            JupyterMessageContent::InterruptRequest(_) => "interrupt_request",
428            JupyterMessageContent::IsCompleteReply(_) => "is_complete_reply",
429            JupyterMessageContent::IsCompleteRequest(_) => "is_complete_request",
430            JupyterMessageContent::KernelInfoReply(_) => "kernel_info_reply",
431            JupyterMessageContent::KernelInfoRequest(_) => "kernel_info_request",
432            JupyterMessageContent::ShutdownReply(_) => "shutdown_reply",
433            JupyterMessageContent::ShutdownRequest(_) => "shutdown_request",
434            JupyterMessageContent::Status(_) => "status",
435            JupyterMessageContent::StreamContent(_) => "stream",
436            JupyterMessageContent::UnknownMessage(unk) => unk.msg_type.as_str(),
437            JupyterMessageContent::UpdateDisplayData(_) => "update_display_data",
438        }
439    }
440
441    pub fn from_type_and_content(msg_type: &str, content: Value) -> serde_json::Result<Self> {
442        match msg_type {
443            "clear_output" => Ok(JupyterMessageContent::ClearOutput(serde_json::from_value(
444                content,
445            )?)),
446
447            "comm_close" => Ok(JupyterMessageContent::CommClose(serde_json::from_value(
448                content,
449            )?)),
450
451            "comm_info_reply" => Ok(JupyterMessageContent::CommInfoReply(
452                serde_json::from_value(content)?,
453            )),
454            "comm_info_request" => Ok(JupyterMessageContent::CommInfoRequest(
455                serde_json::from_value(content)?,
456            )),
457
458            "comm_msg" => Ok(JupyterMessageContent::CommMsg(serde_json::from_value(
459                content,
460            )?)),
461            "comm_open" => Ok(JupyterMessageContent::CommOpen(serde_json::from_value(
462                content,
463            )?)),
464
465            "complete_reply" => Ok(JupyterMessageContent::CompleteReply(
466                serde_json::from_value(content)?,
467            )),
468            "complete_request" => Ok(JupyterMessageContent::CompleteRequest(
469                serde_json::from_value(content)?,
470            )),
471
472            "debug_reply" => Ok(JupyterMessageContent::DebugReply(serde_json::from_value(
473                content,
474            )?)),
475            "debug_request" => Ok(JupyterMessageContent::DebugRequest(serde_json::from_value(
476                content,
477            )?)),
478
479            "display_data" => Ok(JupyterMessageContent::DisplayData(serde_json::from_value(
480                content,
481            )?)),
482
483            "error" => Ok(JupyterMessageContent::ErrorOutput(serde_json::from_value(
484                content,
485            )?)),
486
487            "execute_input" => Ok(JupyterMessageContent::ExecuteInput(serde_json::from_value(
488                content,
489            )?)),
490
491            "execute_reply" => Ok(JupyterMessageContent::ExecuteReply(serde_json::from_value(
492                content,
493            )?)),
494            "execute_request" => Ok(JupyterMessageContent::ExecuteRequest(
495                serde_json::from_value(content)?,
496            )),
497
498            "execute_result" => Ok(JupyterMessageContent::ExecuteResult(
499                serde_json::from_value(content)?,
500            )),
501
502            "history_reply" => Ok(JupyterMessageContent::HistoryReply(serde_json::from_value(
503                content,
504            )?)),
505            "history_request" => Ok(JupyterMessageContent::HistoryRequest(
506                serde_json::from_value(content)?,
507            )),
508
509            "input_reply" => Ok(JupyterMessageContent::InputReply(serde_json::from_value(
510                content,
511            )?)),
512            "input_request" => Ok(JupyterMessageContent::InputRequest(serde_json::from_value(
513                content,
514            )?)),
515
516            "inspect_reply" => Ok(JupyterMessageContent::InspectReply(serde_json::from_value(
517                content,
518            )?)),
519            "inspect_request" => Ok(JupyterMessageContent::InspectRequest(
520                serde_json::from_value(content)?,
521            )),
522
523            "interrupt_reply" => Ok(JupyterMessageContent::InterruptReply(
524                serde_json::from_value(content)?,
525            )),
526            "interrupt_request" => Ok(JupyterMessageContent::InterruptRequest(
527                serde_json::from_value(content)?,
528            )),
529
530            "is_complete_reply" => Ok(JupyterMessageContent::IsCompleteReply(
531                serde_json::from_value(content)?,
532            )),
533            "is_complete_request" => Ok(JupyterMessageContent::IsCompleteRequest(
534                serde_json::from_value(content)?,
535            )),
536
537            "kernel_info_reply" => Ok(JupyterMessageContent::KernelInfoReply(
538                serde_json::from_value(content)?,
539            )),
540            "kernel_info_request" => Ok(JupyterMessageContent::KernelInfoRequest(
541                serde_json::from_value(content)?,
542            )),
543
544            "shutdown_reply" => Ok(JupyterMessageContent::ShutdownReply(
545                serde_json::from_value(content)?,
546            )),
547            "shutdown_request" => Ok(JupyterMessageContent::ShutdownRequest(
548                serde_json::from_value(content)?,
549            )),
550
551            "status" => Ok(JupyterMessageContent::Status(serde_json::from_value(
552                content,
553            )?)),
554
555            "stream" => Ok(JupyterMessageContent::StreamContent(
556                serde_json::from_value(content)?,
557            )),
558
559            "update_display_data" => Ok(JupyterMessageContent::UpdateDisplayData(
560                serde_json::from_value(content)?,
561            )),
562
563            _ => Ok(JupyterMessageContent::UnknownMessage(UnknownMessage {
564                msg_type: msg_type.to_string(),
565                content,
566            })),
567        }
568    }
569}
570
571macro_rules! impl_message_traits {
572    ($($name:ident),*) => {
573        $(
574            impl $name {
575                #[doc = concat!("Create a new `JupyterMessage`, assigning the parent for a `", stringify!($name), "` message.\n")]
576                #[doc = concat!("use jupyter_protocol::", stringify!($name), ";\n")]
584                #[doc = concat!("let child_message = ", stringify!($name), "{\n")]
591                #[must_use]
598                pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
599                    JupyterMessage::new(self.clone(), Some(parent))
600                }
601            }
602
603            impl From<$name> for JupyterMessage {
604                #[doc(hidden)]
605                #[doc = concat!("Create a new `JupyterMessage` for a `", stringify!($name), "`.\n\n")]
606                #[must_use]
609                fn from(content: $name) -> Self {
610                    JupyterMessage::new(content, None)
611                }
612            }
613
614            impl From<$name> for JupyterMessageContent {
615                #[doc = concat!("Create a new `JupyterMessageContent` for a `", stringify!($name), "`.\n\n")]
616                #[must_use]
617                fn from(content: $name) -> Self {
618                    JupyterMessageContent::$name(content)
619                }
620            }
621        )*
622    };
623}
624
625impl From<JupyterMessageContent> for JupyterMessage {
626    fn from(content: JupyterMessageContent) -> Self {
627        JupyterMessage::new(content, None)
628    }
629}
630
631impl_message_traits!(
632    ClearOutput,
633    CommClose,
634    CommInfoReply,
635    CommInfoRequest,
636    CommMsg,
637    CommOpen,
638    CompleteReply,
639    CompleteRequest,
640    DebugReply,
641    DebugRequest,
642    DisplayData,
643    ErrorOutput,
644    ExecuteInput,
645    ExecuteReply,
646    ExecuteRequest,
647    ExecuteResult,
648    HistoryReply,
649    InputReply,
651    InputRequest,
652    InspectReply,
653    InspectRequest,
654    InterruptReply,
655    InterruptRequest,
656    IsCompleteReply,
657    IsCompleteRequest,
658    KernelInfoRequest,
660    ShutdownReply,
661    ShutdownRequest,
662    Status,
663    StreamContent,
664    UpdateDisplayData,
665    UnknownMessage
666);
667
668impl KernelInfoReply {
670    pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
671        JupyterMessage::new(
672            JupyterMessageContent::KernelInfoReply(Box::new(self.clone())),
673            Some(parent),
674        )
675    }
676}
677
678impl From<KernelInfoReply> for JupyterMessage {
679    fn from(content: KernelInfoReply) -> Self {
680        JupyterMessage::new(
681            JupyterMessageContent::KernelInfoReply(Box::new(content)),
682            None,
683        )
684    }
685}
686
687impl From<KernelInfoReply> for JupyterMessageContent {
688    fn from(content: KernelInfoReply) -> Self {
689        JupyterMessageContent::KernelInfoReply(Box::new(content))
690    }
691}
692
693impl HistoryRequest {
694    #[must_use]
720    pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
721        JupyterMessage::new(self.clone(), Some(parent))
722    }
723}
724
725impl From<HistoryRequest> for JupyterMessage {
726    #[doc(hidden)]
727    #[must_use]
731    fn from(content: HistoryRequest) -> Self {
732        JupyterMessage::new(content, None)
733    }
734}
735
736impl From<HistoryRequest> for JupyterMessageContent {
737    #[must_use]
739    fn from(content: HistoryRequest) -> Self {
740        JupyterMessageContent::HistoryRequest(content)
741    }
742}
743
744#[derive(Serialize, Deserialize, Debug, Clone)]
759pub struct UnknownMessage {
760    #[serde(skip_serializing, skip_deserializing)]
761    pub msg_type: String,
762    #[serde(flatten)]
763    pub content: Value,
764}
765impl Default for UnknownMessage {
766    fn default() -> Self {
767        Self {
768            msg_type: "unknown".to_string(),
769            content: Value::Null,
770        }
771    }
772}
773
774impl UnknownMessage {
775    pub fn reply(&self, content: serde_json::Value) -> JupyterMessageContent {
779        JupyterMessageContent::UnknownMessage(UnknownMessage {
780            msg_type: self.msg_type.replace("_request", "_reply"),
781            content,
782        })
783    }
784}
785
786#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
788#[serde(rename_all = "lowercase")]
789pub enum ReplyStatus {
790    #[default]
791    Ok,
792    Error,
793    Aborted,
794}
795
796#[derive(Serialize, Deserialize, Debug, Clone, Default)]
797pub struct ReplyError {
798    pub ename: String,
799    pub evalue: String,
800    pub traceback: Vec<String>,
801}
802
803#[derive(Serialize, Deserialize, Debug, Clone, Default)]
805pub struct ClearOutput {
806    pub wait: bool,
810}
811
812#[derive(Serialize, Deserialize, Debug, Clone)]
816pub struct ExecuteRequest {
817    pub code: String,
818    pub silent: bool,
819    pub store_history: bool,
820    #[serde(serialize_with = "serialize_user_expressions")]
821    pub user_expressions: Option<HashMap<String, String>>,
822    #[serde(default = "default_allow_stdin")]
823    pub allow_stdin: bool,
824    #[serde(default = "default_stop_on_error")]
825    pub stop_on_error: bool,
826}
827
828fn serialize_user_expressions<S>(
832    user_expressions: &Option<HashMap<String, String>>,
833    serializer: S,
834) -> Result<S::Ok, S::Error>
835where
836    S: serde::Serializer,
837{
838    match user_expressions {
839        Some(user_expressions) => user_expressions.serialize(serializer),
840        None => serde_json::Map::new().serialize(serializer),
841    }
842}
843
844fn default_allow_stdin() -> bool {
845    false
846}
847
848fn default_stop_on_error() -> bool {
849    true
850}
851
852impl ExecuteRequest {
853    pub fn new(code: String) -> Self {
854        Self {
855            code,
856            ..Default::default()
857        }
858    }
859}
860
861impl Default for ExecuteRequest {
862    fn default() -> Self {
863        Self {
864            code: "".to_string(),
865            silent: false,
866            store_history: true,
867            user_expressions: None,
868            allow_stdin: false,
869            stop_on_error: true,
870        }
871    }
872}
873
874#[derive(Serialize, Deserialize, Debug, Clone)]
882pub struct ExecuteReply {
883    pub status: ReplyStatus,
884    pub execution_count: ExecutionCount,
885
886    #[serde(default)]
887    pub payload: Vec<Payload>,
888    pub user_expressions: Option<HashMap<String, String>>,
889
890    #[serde(flatten, skip_serializing_if = "Option::is_none")]
891    pub error: Option<Box<ReplyError>>,
892}
893impl Default for ExecuteReply {
894    fn default() -> Self {
895        Self {
896            status: ReplyStatus::Ok,
897            execution_count: ExecutionCount::new(0),
898            payload: Vec::new(),
899            user_expressions: None,
900            error: None,
901        }
902    }
903}
904
905#[derive(Serialize, Deserialize, Debug, Clone)]
910#[serde(rename_all = "snake_case")]
911#[serde(tag = "source")]
912pub enum Payload {
913    Page {
914        data: Media,
915        start: usize,
916    },
917    SetNextInput {
918        text: String,
919        replace: bool,
920    },
921    EditMagic {
922        filename: String,
923        line_number: usize,
924    },
925    AskExit {
926        keepkernel: bool,
928    },
929}
930
931#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
935pub struct KernelInfoRequest {}
936
937#[derive(Serialize, Deserialize, Debug, Clone)]
941pub struct KernelInfoReply {
942    pub status: ReplyStatus,
943    pub protocol_version: String,
944    pub implementation: String,
945    pub implementation_version: String,
946    pub language_info: LanguageInfo,
947    pub banner: String,
948    pub help_links: Vec<HelpLink>,
949    #[serde(default = "default_debugger")]
950    pub debugger: bool,
951    #[serde(flatten, skip_serializing_if = "Option::is_none")]
952    pub error: Option<Box<ReplyError>>,
953}
954
955fn default_debugger() -> bool {
956    false
957}
958
959#[derive(Serialize, Deserialize, Debug, Clone)]
960#[serde(untagged)]
961pub enum CodeMirrorMode {
962    Simple(String),
963    CustomMode { name: String, version: usize },
964}
965
966#[derive(Serialize, Deserialize, Debug, Clone)]
967pub struct CodeMirrorModeObject {
968    pub name: String,
969    pub version: usize,
970}
971
972impl CodeMirrorMode {
973    pub fn typescript() -> Self {
974        Self::Simple("typescript".to_string())
975    }
976
977    pub fn python() -> Self {
978        Self::Simple("python".to_string())
979    }
980
981    pub fn ipython_code_mirror_mode() -> Self {
982        Self::CustomMode {
983            name: "ipython".to_string(),
984            version: 3,
985        }
986    }
987}
988
989#[derive(Serialize, Deserialize, Debug, Clone)]
990pub struct LanguageInfo {
991    pub name: String,
992    pub version: String,
993    pub mimetype: String,
994    pub file_extension: String,
995    pub pygments_lexer: String,
996    pub codemirror_mode: CodeMirrorMode,
997    pub nbconvert_exporter: String,
998}
999
1000#[derive(Serialize, Deserialize, Debug, Clone)]
1001pub struct HelpLink {
1002    pub text: String,
1003    pub url: String,
1004}
1005
1006#[derive(Serialize, Deserialize, Debug, Clone)]
1007pub enum Stdio {
1008    #[serde(rename = "stdout")]
1009    Stdout,
1010    #[serde(rename = "stderr")]
1011    Stderr,
1012}
1013
1014#[derive(Serialize, Deserialize, Debug, Clone)]
1056pub struct StreamContent {
1057    pub name: Stdio,
1058    pub text: String,
1059}
1060impl Default for StreamContent {
1061    fn default() -> Self {
1062        Self {
1063            name: Stdio::Stdout,
1064            text: String::new(),
1065        }
1066    }
1067}
1068
1069impl StreamContent {
1070    pub fn stdout(text: &str) -> Self {
1071        Self {
1072            name: Stdio::Stdout,
1073            text: text.to_string(),
1074        }
1075    }
1076
1077    pub fn stderr(text: &str) -> Self {
1078        Self {
1079            name: Stdio::Stderr,
1080            text: text.to_string(),
1081        }
1082    }
1083}
1084
1085#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1087pub struct Transient {
1088    #[serde(skip_serializing_if = "Option::is_none")]
1089    pub display_id: Option<String>,
1090}
1091
1092#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1132pub struct DisplayData {
1133    pub data: Media,
1134    pub metadata: serde_json::Map<String, Value>,
1135    #[serde(default, skip_serializing_if = "Option::is_none")]
1136    pub transient: Option<Transient>,
1137}
1138
1139impl DisplayData {
1140    pub fn new(data: Media) -> Self {
1141        Self {
1142            data,
1143            metadata: Default::default(),
1144            transient: Default::default(),
1145        }
1146    }
1147}
1148
1149impl From<Vec<MediaType>> for DisplayData {
1150    fn from(content: Vec<MediaType>) -> Self {
1151        Self::new(Media::new(content))
1152    }
1153}
1154
1155impl From<MediaType> for DisplayData {
1156    fn from(content: MediaType) -> Self {
1157        Self::new(Media::new(vec![content]))
1158    }
1159}
1160
1161#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1164pub struct UpdateDisplayData {
1165    pub data: Media,
1166    pub metadata: serde_json::Map<String, Value>,
1167    pub transient: Transient,
1168}
1169
1170impl UpdateDisplayData {
1171    pub fn new(data: Media, display_id: &str) -> Self {
1172        Self {
1173            data,
1174            metadata: Default::default(),
1175            transient: Transient {
1176                display_id: Some(display_id.to_string()),
1177            },
1178        }
1179    }
1180}
1181
1182#[derive(Serialize, Deserialize, Debug, Clone)]
1188pub struct ExecuteInput {
1189    pub code: String,
1190    pub execution_count: ExecutionCount,
1191}
1192impl Default for ExecuteInput {
1193    fn default() -> Self {
1194        Self {
1195            code: String::new(),
1196            execution_count: ExecutionCount::new(0),
1197        }
1198    }
1199}
1200
1201#[derive(Serialize, Deserialize, Debug, Clone)]
1225pub struct ExecuteResult {
1226    pub execution_count: ExecutionCount,
1227    pub data: Media,
1228    pub metadata: serde_json::Map<String, Value>,
1229    pub transient: Option<Transient>,
1230}
1231impl Default for ExecuteResult {
1232    fn default() -> Self {
1233        Self {
1234            execution_count: ExecutionCount::new(0),
1235            data: Media::default(),
1236            metadata: serde_json::Map::new(),
1237            transient: None,
1238        }
1239    }
1240}
1241
1242impl ExecuteResult {
1243    pub fn new(execution_count: ExecutionCount, data: Media) -> Self {
1244        Self {
1245            execution_count,
1246            data,
1247            metadata: Default::default(),
1248            transient: None,
1249        }
1250    }
1251}
1252
1253impl From<(ExecutionCount, Vec<MediaType>)> for ExecuteResult {
1254    fn from((execution_count, content): (ExecutionCount, Vec<MediaType>)) -> Self {
1255        Self::new(execution_count, content.into())
1256    }
1257}
1258
1259impl From<(ExecutionCount, MediaType)> for ExecuteResult {
1260    fn from((execution_count, content): (ExecutionCount, MediaType)) -> Self {
1261        Self::new(execution_count, content.into())
1262    }
1263}
1264
1265#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1271pub struct ErrorOutput {
1272    pub ename: String,
1273    pub evalue: String,
1274    pub traceback: Vec<String>,
1275}
1276
1277#[derive(Serialize, Deserialize, Debug, Clone)]
1305pub struct CommOpen {
1306    pub comm_id: CommId,
1307    pub target_name: String,
1308    pub data: serde_json::Map<String, Value>,
1309}
1310impl Default for CommOpen {
1311    fn default() -> Self {
1312        Self {
1313            comm_id: CommId("".to_string()),
1314            target_name: String::new(),
1315            data: serde_json::Map::new(),
1316        }
1317    }
1318}
1319
1320#[derive(Serialize, Deserialize, Debug, Clone)]
1339pub struct CommMsg {
1340    pub comm_id: CommId,
1341    pub data: serde_json::Map<String, Value>,
1342}
1343impl Default for CommMsg {
1344    fn default() -> Self {
1345        Self {
1346            comm_id: CommId("".to_string()),
1347            data: serde_json::Map::new(),
1348        }
1349    }
1350}
1351
1352#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1353pub struct CommInfoRequest {
1354    pub target_name: String,
1355}
1356
1357#[derive(Eq, Hash, PartialEq, Serialize, Deserialize, Debug, Clone)]
1358pub struct CommId(pub String);
1359
1360impl From<CommId> for String {
1361    fn from(comm_id: CommId) -> Self {
1362        comm_id.0
1363    }
1364}
1365
1366impl From<String> for CommId {
1367    fn from(comm_id: String) -> Self {
1368        Self(comm_id)
1369    }
1370}
1371
1372#[derive(Serialize, Deserialize, Debug, Clone)]
1373pub struct CommInfo {
1374    pub target_name: String,
1375}
1376
1377#[derive(Serialize, Deserialize, Debug, Clone)]
1378pub struct CommInfoReply {
1379    pub status: ReplyStatus,
1380    pub comms: HashMap<CommId, CommInfo>,
1381    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1383    pub error: Option<Box<ReplyError>>,
1384}
1385impl Default for CommInfoReply {
1386    fn default() -> Self {
1387        Self {
1388            status: ReplyStatus::Ok,
1389            comms: HashMap::new(),
1390            error: None,
1391        }
1392    }
1393}
1394
1395#[derive(Serialize, Deserialize, Debug, Clone)]
1400pub struct CommClose {
1401    pub comm_id: CommId,
1402    pub data: serde_json::Map<String, Value>,
1403}
1404impl Default for CommClose {
1405    fn default() -> Self {
1406        Self {
1407            comm_id: CommId("".to_string()),
1408            data: serde_json::Map::new(),
1409        }
1410    }
1411}
1412
1413#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1414pub struct ShutdownRequest {
1421    pub restart: bool,
1422}
1423
1424#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1425pub struct InterruptRequest {}
1433
1434#[derive(Serialize, Deserialize, Debug, Clone)]
1435pub struct InterruptReply {
1442    pub status: ReplyStatus,
1443
1444    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1445    pub error: Option<Box<ReplyError>>,
1446}
1447
1448impl Default for InterruptReply {
1449    fn default() -> Self {
1450        Self::new()
1451    }
1452}
1453
1454impl InterruptReply {
1455    pub fn new() -> Self {
1456        Self {
1457            status: ReplyStatus::Ok,
1458            error: None,
1459        }
1460    }
1461}
1462
1463#[derive(Serialize, Deserialize, Debug, Clone)]
1464pub struct ShutdownReply {
1471    pub restart: bool,
1472    pub status: ReplyStatus,
1473
1474    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1475    pub error: Option<Box<ReplyError>>,
1476}
1477impl Default for ShutdownReply {
1478    fn default() -> Self {
1479        Self {
1480            restart: false,
1481            status: ReplyStatus::Ok,
1482            error: None,
1483        }
1484    }
1485}
1486
1487#[derive(Serialize, Deserialize, Debug, Clone)]
1488pub struct InputRequest {
1495    pub prompt: String,
1496    pub password: bool,
1497}
1498impl Default for InputRequest {
1499    fn default() -> Self {
1500        Self {
1501            prompt: "> ".to_string(),
1502            password: false,
1503        }
1504    }
1505}
1506
1507#[derive(Serialize, Deserialize, Debug, Clone)]
1508pub struct InputReply {
1515    pub value: String,
1516
1517    pub status: ReplyStatus,
1518    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1519    pub error: Option<Box<ReplyError>>,
1520}
1521impl Default for InputReply {
1522    fn default() -> Self {
1523        Self {
1524            value: String::new(),
1525            status: ReplyStatus::Ok,
1526            error: None,
1527        }
1528    }
1529}
1530
1531#[derive(Serialize, Deserialize, Debug, Clone)]
1537pub struct InspectRequest {
1538    pub code: String,
1541    pub cursor_pos: usize,
1543    pub detail_level: Option<usize>,
1548}
1549impl Default for InspectRequest {
1550    fn default() -> Self {
1551        Self {
1552            code: String::new(),
1553            cursor_pos: 0,
1554            detail_level: Some(0),
1555        }
1556    }
1557}
1558
1559#[derive(Serialize, Deserialize, Debug, Clone)]
1560pub struct InspectReply {
1561    pub found: bool,
1562    pub data: Media,
1563    pub metadata: serde_json::Map<String, Value>,
1564
1565    pub status: ReplyStatus,
1566    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1567    pub error: Option<Box<ReplyError>>,
1568}
1569impl Default for InspectReply {
1570    fn default() -> Self {
1571        Self {
1572            found: false,
1573            data: Media::default(),
1574            metadata: serde_json::Map::new(),
1575            status: ReplyStatus::Ok,
1576            error: None,
1577        }
1578    }
1579}
1580
1581#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1585pub struct CompleteRequest {
1586    pub code: String,
1587    pub cursor_pos: usize,
1588}
1589
1590#[derive(Serialize, Deserialize, Debug, Clone)]
1594pub struct CompleteReply {
1595    pub matches: Vec<String>,
1596    pub cursor_start: usize,
1597    pub cursor_end: usize,
1598    pub metadata: serde_json::Map<String, Value>,
1599
1600    pub status: ReplyStatus,
1601    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1602    pub error: Option<Box<ReplyError>>,
1603}
1604impl Default for CompleteReply {
1605    fn default() -> Self {
1606        Self {
1607            matches: Vec::new(),
1608            cursor_start: 0,
1609            cursor_end: 0,
1610            metadata: serde_json::Map::new(),
1611            status: ReplyStatus::Ok,
1612            error: None,
1613        }
1614    }
1615}
1616
1617#[derive(Serialize, Deserialize, Debug, Clone)]
1618pub struct DebugRequest {
1619    #[serde(flatten)]
1620    pub content: Value,
1621}
1622impl Default for DebugRequest {
1623    fn default() -> Self {
1624        Self {
1625            content: Value::Null,
1626        }
1627    }
1628}
1629
1630#[derive(Serialize, Deserialize, Debug, Clone)]
1631pub struct DebugReply {
1632    #[serde(flatten)]
1633    pub content: Value,
1634}
1635impl Default for DebugReply {
1636    fn default() -> Self {
1637        Self {
1638            content: Value::Null,
1639        }
1640    }
1641}
1642
1643#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1644#[serde(rename_all = "snake_case")]
1645pub enum IsCompleteReplyStatus {
1646    Incomplete,
1649    Complete,
1651    Invalid,
1653    Unknown,
1658}
1659
1660#[derive(Serialize, Deserialize, Debug, Clone)]
1661pub struct IsCompleteReply {
1662    pub status: IsCompleteReplyStatus,
1665    pub indent: String,
1670}
1671impl Default for IsCompleteReply {
1672    fn default() -> Self {
1673        Self {
1674            status: IsCompleteReplyStatus::Unknown,
1675            indent: String::new(),
1676        }
1677    }
1678}
1679
1680impl IsCompleteReply {
1681    pub fn new(status: IsCompleteReplyStatus, indent: String) -> Self {
1682        Self { status, indent }
1683    }
1684
1685    pub fn incomplete(indent: String) -> Self {
1686        Self::new(IsCompleteReplyStatus::Incomplete, indent)
1687    }
1688
1689    pub fn complete() -> Self {
1690        Self::new(IsCompleteReplyStatus::Complete, String::new())
1691    }
1692
1693    pub fn invalid() -> Self {
1694        Self::new(IsCompleteReplyStatus::Invalid, String::new())
1695    }
1696
1697    pub fn unknown() -> Self {
1698        Self::new(IsCompleteReplyStatus::Unknown, String::new())
1699    }
1700}
1701
1702#[derive(Serialize, Deserialize, Debug, Clone)]
1703#[serde(tag = "hist_access_type")]
1704pub enum HistoryRequest {
1705    #[serde(rename = "range")]
1706    Range {
1707        session: Option<i32>,
1708        start: i32,
1709        stop: i32,
1710        output: bool,
1711        raw: bool,
1712    },
1713    #[serde(rename = "tail")]
1714    Tail { n: i32, output: bool, raw: bool },
1715    #[serde(rename = "search")]
1716    Search {
1717        pattern: String,
1718        unique: bool,
1719        output: bool,
1720        raw: bool,
1721    },
1722}
1723impl Default for HistoryRequest {
1724    fn default() -> Self {
1725        Self::Range {
1726            session: None,
1727            start: 0,
1728            stop: 0,
1729            output: false,
1730            raw: false,
1731        }
1732    }
1733}
1734
1735#[derive(Serialize, Deserialize, Debug, Clone)]
1736#[serde(untagged)]
1737pub enum HistoryEntry {
1738    Input(usize, usize, String),
1741    InputOutput(usize, usize, (String, String)),
1744}
1745
1746#[derive(Serialize, Deserialize, Debug, Clone)]
1750pub struct HistoryReply {
1751    pub history: Vec<HistoryEntry>,
1752
1753    pub status: ReplyStatus,
1754    #[serde(flatten, skip_serializing_if = "Option::is_none")]
1755    pub error: Option<Box<ReplyError>>,
1756}
1757impl Default for HistoryReply {
1758    fn default() -> Self {
1759        Self {
1760            history: Vec::new(),
1761            status: ReplyStatus::Ok,
1762            error: None,
1763        }
1764    }
1765}
1766
1767impl HistoryReply {
1768    pub fn new(history: Vec<HistoryEntry>) -> Self {
1769        Self {
1770            history,
1771            status: ReplyStatus::Ok,
1772            error: None,
1773        }
1774    }
1775}
1776
1777#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1781pub struct IsCompleteRequest {
1782    pub code: String,
1783}
1784
1785#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1786#[serde(rename_all = "lowercase")]
1787pub enum ExecutionState {
1788    Busy,
1789    Idle,
1790}
1791
1792impl ExecutionState {
1793    pub fn as_str(&self) -> &str {
1794        match self {
1795            ExecutionState::Busy => "busy",
1796            ExecutionState::Idle => "idle",
1797        }
1798    }
1799}
1800
1801#[derive(Serialize, Deserialize, Debug, Clone)]
1805pub struct Status {
1806    pub execution_state: ExecutionState,
1807}
1808impl Default for Status {
1809    fn default() -> Self {
1810        Self {
1811            execution_state: ExecutionState::Idle,
1812        }
1813    }
1814}
1815
1816impl Status {
1817    pub fn busy() -> Self {
1818        Self {
1819            execution_state: ExecutionState::Busy,
1820        }
1821    }
1822
1823    pub fn idle() -> Self {
1824        Self {
1825            execution_state: ExecutionState::Idle,
1826        }
1827    }
1828}
1829
1830#[cfg(test)]
1831mod test {
1832    use serde_json::json;
1833
1834    use super::*;
1835
1836    #[test]
1837    fn test_execute_request_serialize() {
1838        let request = ExecuteRequest {
1839            code: "print('Hello, World!')".to_string(),
1840            silent: false,
1841            store_history: true,
1842            user_expressions: Some(HashMap::new()),
1843            allow_stdin: false,
1844            stop_on_error: true,
1845        };
1846        let request_value = serde_json::to_value(request).unwrap();
1847
1848        let expected_request_value = serde_json::json!({
1849            "code": "print('Hello, World!')",
1850            "silent": false,
1851            "store_history": true,
1852            "user_expressions": {},
1853            "allow_stdin": false,
1854            "stop_on_error": true
1855        });
1856
1857        assert_eq!(request_value, expected_request_value);
1858    }
1859
1860    #[test]
1861    fn test_execute_request_user_expressions_serializes_to_empty_dict() {
1862        let request = ExecuteRequest {
1863            code: "print('Hello, World!')".to_string(),
1864            silent: false,
1865            store_history: true,
1866            user_expressions: None,
1867            allow_stdin: false,
1868            stop_on_error: true,
1869        };
1870        let request_value = serde_json::to_value(request).unwrap();
1871
1872        let expected_request_value = serde_json::json!({
1873            "code": "print('Hello, World!')",
1874            "silent": false,
1875            "store_history": true,
1876            "user_expressions": {},
1877            "allow_stdin": false,
1878            "stop_on_error": true
1879        });
1880
1881        assert_eq!(request_value, expected_request_value);
1882    }
1883
1884    #[test]
1885    fn test_into_various() {
1886        let kernel_info_request = KernelInfoRequest {};
1887        let content: JupyterMessageContent = kernel_info_request.clone().into();
1888        let message: JupyterMessage = content.into();
1889        assert!(message.parent_header.is_none());
1890        match message.content {
1891            JupyterMessageContent::KernelInfoRequest(req) => {
1892                assert_eq!(req, kernel_info_request);
1893            }
1894            _ => panic!("Expected KernelInfoRequest"),
1895        }
1896
1897        let kernel_info_request = KernelInfoRequest {};
1898        let message: JupyterMessage = kernel_info_request.clone().into();
1899        assert!(message.parent_header.is_none());
1900        match message.content {
1901            JupyterMessageContent::KernelInfoRequest(req) => {
1902                assert_eq!(req, kernel_info_request);
1903            }
1904            _ => panic!("Expected KernelInfoRequest"),
1905        }
1906    }
1907
1908    #[test]
1909    fn test_default() {
1910        let msg: JupyterMessage = ExecuteRequest {
1911            code: "import this".to_string(),
1912            ..Default::default()
1913        }
1914        .into();
1915
1916        assert_eq!(msg.header.msg_type, "execute_request");
1917        assert_eq!(msg.header.msg_id.len(), 36);
1918
1919        match msg.content {
1920            JupyterMessageContent::ExecuteRequest(req) => {
1921                assert_eq!(req.code, "import this");
1922                assert!(!req.silent);
1923                assert!(req.store_history);
1924                assert_eq!(req.user_expressions, None);
1925                assert!(!req.allow_stdin);
1926                assert!(req.stop_on_error);
1927            }
1928            _ => panic!("Expected ExecuteRequest"),
1929        }
1930    }
1931
1932    #[test]
1933    fn test_deserialize_payload() {
1934        let raw_execute_reply_content = r#"
1935        {
1936            "status": "ok",
1937            "execution_count": 1,
1938            "payload": [{
1939                "source": "page",
1940                "data": {
1941                    "text/html": "<h1>Hello</h1>",
1942                    "text/plain": "Hello"
1943                },
1944                "start": 0
1945            }],
1946            "user_expressions": {}
1947        }
1948        "#;
1949
1950        let execute_reply: ExecuteReply = serde_json::from_str(raw_execute_reply_content).unwrap();
1951
1952        assert_eq!(execute_reply.status, ReplyStatus::Ok);
1953        assert_eq!(execute_reply.execution_count, ExecutionCount::new(1));
1954
1955        let payload = execute_reply.payload.clone();
1956
1957        assert_eq!(payload.len(), 1);
1958        let payload = payload.first().unwrap();
1959
1960        let media = match payload {
1961            Payload::Page { data, .. } => data,
1962            _ => panic!("Expected Page payload type"),
1963        };
1964
1965        let media = serde_json::to_value(media).unwrap();
1966
1967        let expected_media = serde_json::json!({
1968            "text/html": "<h1>Hello</h1>",
1969            "text/plain": "Hello"
1970        });
1971
1972        assert_eq!(media, expected_media);
1973    }
1974
1975    #[test]
1976    pub fn test_display_data_various_data() {
1977        let display_data = DisplayData {
1978            data: serde_json::from_value(json!({
1979                "text/plain": "Hello, World!",
1980                "text/html": "<h1>Hello, World!</h1>",
1981                "application/json": {
1982                    "hello": "world",
1983                    "foo": "bar",
1984                    "ok": [1, 2, 3],
1985                }
1986            }))
1987            .unwrap(),
1988            ..Default::default()
1989        };
1990
1991        let display_data_value = serde_json::to_value(display_data).unwrap();
1992
1993        let expected_display_data_value = serde_json::json!({
1994            "data": {
1995                "text/plain": "Hello, World!",
1996                "text/html": "<h1>Hello, World!</h1>",
1997                "application/json": {
1998                    "hello": "world",
1999                    "foo": "bar",
2000                    "ok": [1, 2, 3]
2001                }
2002            },
2003            "metadata": {}
2004        });
2005
2006        assert_eq!(display_data_value, expected_display_data_value);
2007    }
2008
2009    use std::mem::size_of;
2010
2011    macro_rules! size_of_variant {
2012        ($variant:ty) => {
2013            let size = size_of::<$variant>();
2014            println!("The size of {} is: {} bytes", stringify!($variant), size);
2015
2016            assert!(size <= 96);
2017        };
2018    }
2019
2020    #[test]
2021    fn test_enum_variant_sizes() {
2022        size_of_variant!(ClearOutput);
2023        size_of_variant!(CommClose);
2024        size_of_variant!(CommInfoReply);
2025        size_of_variant!(CommInfoRequest);
2026        size_of_variant!(CommMsg);
2027        size_of_variant!(CommOpen);
2028        size_of_variant!(CompleteReply);
2029        size_of_variant!(CompleteRequest);
2030        size_of_variant!(DebugReply);
2031        size_of_variant!(DebugRequest);
2032        size_of_variant!(DisplayData);
2033        size_of_variant!(ErrorOutput);
2034        size_of_variant!(ExecuteInput);
2035        size_of_variant!(ExecuteReply);
2036        size_of_variant!(ExecuteRequest);
2037        size_of_variant!(ExecuteResult);
2038        size_of_variant!(HistoryReply);
2039        size_of_variant!(HistoryRequest);
2040        size_of_variant!(InputReply);
2041        size_of_variant!(InputRequest);
2042        size_of_variant!(InspectReply);
2043        size_of_variant!(InspectRequest);
2044        size_of_variant!(InterruptReply);
2045        size_of_variant!(InterruptRequest);
2046        size_of_variant!(IsCompleteReply);
2047        size_of_variant!(IsCompleteRequest);
2048        size_of_variant!(Box<KernelInfoReply>);
2049        size_of_variant!(KernelInfoRequest);
2050        size_of_variant!(ShutdownReply);
2051        size_of_variant!(ShutdownRequest);
2052        size_of_variant!(Status);
2053        size_of_variant!(StreamContent);
2054        size_of_variant!(UnknownMessage);
2055        size_of_variant!(UpdateDisplayData);
2056    }
2057
2058    #[test]
2059    fn test_jupyter_message_content_enum_size() {
2060        let size = size_of::<JupyterMessageContent>();
2061        println!("The size of JupyterMessageContent is: {}", size);
2062        assert!(size > 0);
2063        assert!(size <= 96);
2064    }
2065
2066    #[test]
2067    fn test_jupyter_message_parent_header_serializes_to_empty_dict() {
2068        let request = ExecuteRequest {
2069            code: "1 + 1".to_string(),
2070            ..Default::default()
2071        };
2072        let message = JupyterMessage::from(request);
2073
2074        let serialized_message = serde_json::to_value(message).unwrap();
2075
2076        let parent_header = serialized_message.get("parent_header").unwrap();
2078        assert!(parent_header.is_object());
2079        assert!(parent_header.as_object().unwrap().is_empty());
2080    }
2081
2082    #[test]
2083    fn test_user_expressions_serialization() {
2084        let request = ExecuteRequest {
2085            code: "pass".to_string(),
2086            silent: false,
2087            store_history: true,
2088            user_expressions: Some(HashMap::from([(
2089                String::from("expression"),
2090                String::from("42 + 7"),
2091            )])),
2092            allow_stdin: false,
2093            stop_on_error: true,
2094        };
2095        let request_value = serde_json::to_value(request.clone()).unwrap();
2096
2097        let expected_request_value = serde_json::json!({
2098            "code": "pass",
2099            "silent": false,
2100            "store_history": true,
2101            "user_expressions": {"expression": "42 + 7"},
2102            "allow_stdin": false,
2103            "stop_on_error": true
2104        });
2105
2106        assert_eq!(request_value, expected_request_value);
2107
2108        let deserialized_request: ExecuteRequest = serde_json::from_value(request_value).unwrap();
2109        assert_eq!(
2110            deserialized_request.user_expressions,
2111            request.user_expressions
2112        );
2113    }
2114}