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}