1use crate::{time, JupyterError};
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
171fn deserialize_parent_header<'de, D>(deserializer: D) -> Result<Option<Header>, D::Error>
177where
178 D: serde::Deserializer<'de>,
179{
180 use serde::de::Error;
181 let value = Value::deserialize(deserializer)?;
182 if value.is_null() {
183 Ok(None)
184 } else if let Some(obj) = value.as_object() {
185 if obj.is_empty() {
186 Ok(None)
187 } else {
188 serde_json::from_value(Value::Object(obj.clone()))
190 .map(Some)
191 .map_err(D::Error::custom)
192 }
193 } else {
194 serde_json::from_value(value)
196 .map(Some)
197 .map_err(D::Error::custom)
198 }
199}
200
201#[derive(Deserialize, Serialize, Clone)]
250pub struct JupyterMessage {
251 #[serde(skip_serializing, skip_deserializing)]
252 pub zmq_identities: Vec<Bytes>,
253 pub header: Header,
254 #[serde(
255 serialize_with = "serialize_parent_header",
256 deserialize_with = "deserialize_parent_header"
257 )]
258 pub parent_header: Option<Header>,
259 pub metadata: Value,
260 pub content: JupyterMessageContent,
261 #[serde(skip_serializing, skip_deserializing)]
262 pub buffers: Vec<Bytes>,
263 pub channel: Option<Channel>,
264}
265
266impl JupyterMessage {
267 pub fn new(
268 content: impl Into<JupyterMessageContent>,
269 parent: Option<&JupyterMessage>,
270 ) -> JupyterMessage {
271 let session = match parent {
275 Some(parent) => parent.header.session.clone(),
276 None => Uuid::new_v4().to_string(),
277 };
278
279 let content = content.into();
280
281 let header = Header {
282 msg_id: Uuid::new_v4().to_string(),
283 username: "runtimelib".to_string(),
284 session,
285 date: time::utc_now(),
286 msg_type: content.message_type().to_owned(),
287 version: "5.3".to_string(),
288 };
289
290 JupyterMessage {
291 zmq_identities: parent.map_or(Vec::new(), |parent| parent.zmq_identities.clone()),
292 header,
293 parent_header: parent.map(|parent| parent.header.clone()),
294 metadata: json!({}),
295 content,
296 buffers: Vec::new(),
297 channel: None,
298 }
299 }
300
301 pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
302 self.metadata = metadata;
303 self
304 }
305
306 pub fn with_buffers(mut self, buffers: Vec<Bytes>) -> Self {
307 self.buffers = buffers;
308 self
309 }
310
311 pub fn with_parent(mut self, parent: &JupyterMessage) -> Self {
312 self.header.session.clone_from(&parent.header.session);
313 self.parent_header = Some(parent.header.clone());
314 self.zmq_identities.clone_from(&parent.zmq_identities);
315 self
316 }
317
318 pub fn with_zmq_identities(mut self, zmq_identities: Vec<Bytes>) -> Self {
319 self.zmq_identities = zmq_identities;
320 self
321 }
322
323 pub fn with_session(mut self, session: &str) -> Self {
324 self.header.session = session.to_string();
325 self
326 }
327
328 pub fn message_type(&self) -> &str {
329 self.content.message_type()
330 }
331
332 pub fn from_value(message: Value) -> Result<JupyterMessage, JupyterError> {
333 let message = serde_json::from_value::<UnknownJupyterMessage>(message)?;
334
335 let content =
336 JupyterMessageContent::from_type_and_content(&message.header.msg_type, message.content);
337
338 let content = match content {
339 Ok(content) => content,
340 Err(err) => {
341 return Err(JupyterError::ParseError {
342 msg_type: message.header.msg_type,
343 source: err,
344 })
345 }
346 };
347
348 let message = JupyterMessage {
349 zmq_identities: Vec::new(),
350 header: message.header,
351 parent_header: message.parent_header,
352 metadata: message.metadata,
353 content,
354 buffers: message.buffers,
355 channel: None,
356 };
357
358 Ok(message)
359 }
360}
361
362impl fmt::Debug for JupyterMessage {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 writeln!(
365 f,
366 "\nHeader: {}",
367 serde_json::to_string_pretty(&self.header).unwrap()
368 )?;
369 writeln!(
370 f,
371 "Parent header: {}",
372 if let Some(parent_header) = self.parent_header.as_ref() {
373 serde_json::to_string_pretty(parent_header).unwrap()
374 } else {
375 serde_json::to_string_pretty(&serde_json::Map::new()).unwrap()
376 }
377 )?;
378 writeln!(
379 f,
380 "Metadata: {}",
381 serde_json::to_string_pretty(&self.metadata).unwrap()
382 )?;
383 writeln!(
384 f,
385 "Content: {}\n",
386 serde_json::to_string_pretty(&self.content).unwrap()
387 )?;
388 Ok(())
389 }
390}
391
392#[derive(Serialize, Deserialize, Debug, Clone)]
393#[serde(untagged)]
394pub enum JupyterMessageContent {
395 ClearOutput(ClearOutput),
396 CommClose(CommClose),
397 CommInfoReply(CommInfoReply),
398 CommInfoRequest(CommInfoRequest),
399 CommMsg(CommMsg),
400 CommOpen(CommOpen),
401 CompleteReply(CompleteReply),
402 CompleteRequest(CompleteRequest),
403 DebugReply(DebugReply),
404 DebugRequest(DebugRequest),
405 DisplayData(DisplayData),
406 ErrorOutput(ErrorOutput),
407 ExecuteInput(ExecuteInput),
408 ExecuteReply(ExecuteReply),
409 ExecuteRequest(ExecuteRequest),
410 ExecuteResult(ExecuteResult),
411 HistoryReply(HistoryReply),
412 HistoryRequest(HistoryRequest),
413 InputReply(InputReply),
414 InputRequest(InputRequest),
415 InspectReply(InspectReply),
416 InspectRequest(InspectRequest),
417 InterruptReply(InterruptReply),
418 InterruptRequest(InterruptRequest),
419 IoPubWelcome(IoPubWelcome),
420 IsCompleteReply(IsCompleteReply),
421 IsCompleteRequest(IsCompleteRequest),
422 KernelInfoReply(Box<KernelInfoReply>),
425 KernelInfoRequest(KernelInfoRequest),
426 ShutdownReply(ShutdownReply),
427 ShutdownRequest(ShutdownRequest),
428 Status(Status),
429 StreamContent(StreamContent),
430 UnknownMessage(UnknownMessage),
431 UpdateDisplayData(UpdateDisplayData),
432}
433
434impl JupyterMessageContent {
435 pub fn message_type(&self) -> &str {
436 match self {
437 JupyterMessageContent::ClearOutput(_) => "clear_output",
438 JupyterMessageContent::CommClose(_) => "comm_close",
439 JupyterMessageContent::CommInfoReply(_) => "comm_info_reply",
440 JupyterMessageContent::CommInfoRequest(_) => "comm_info_request",
441 JupyterMessageContent::CommMsg(_) => "comm_msg",
442 JupyterMessageContent::CommOpen(_) => "comm_open",
443 JupyterMessageContent::CompleteReply(_) => "complete_reply",
444 JupyterMessageContent::CompleteRequest(_) => "complete_request",
445 JupyterMessageContent::DebugReply(_) => "debug_reply",
446 JupyterMessageContent::DebugRequest(_) => "debug_request",
447 JupyterMessageContent::DisplayData(_) => "display_data",
448 JupyterMessageContent::ErrorOutput(_) => "error",
449 JupyterMessageContent::ExecuteInput(_) => "execute_input",
450 JupyterMessageContent::ExecuteReply(_) => "execute_reply",
451 JupyterMessageContent::ExecuteRequest(_) => "execute_request",
452 JupyterMessageContent::ExecuteResult(_) => "execute_result",
453 JupyterMessageContent::HistoryReply(_) => "history_reply",
454 JupyterMessageContent::HistoryRequest(_) => "history_request",
455 JupyterMessageContent::InputReply(_) => "input_reply",
456 JupyterMessageContent::InputRequest(_) => "input_request",
457 JupyterMessageContent::InspectReply(_) => "inspect_reply",
458 JupyterMessageContent::InspectRequest(_) => "inspect_request",
459 JupyterMessageContent::InterruptReply(_) => "interrupt_reply",
460 JupyterMessageContent::InterruptRequest(_) => "interrupt_request",
461 JupyterMessageContent::IoPubWelcome(_) => "iopub_welcome",
462 JupyterMessageContent::IsCompleteReply(_) => "is_complete_reply",
463 JupyterMessageContent::IsCompleteRequest(_) => "is_complete_request",
464 JupyterMessageContent::KernelInfoReply(_) => "kernel_info_reply",
465 JupyterMessageContent::KernelInfoRequest(_) => "kernel_info_request",
466 JupyterMessageContent::ShutdownReply(_) => "shutdown_reply",
467 JupyterMessageContent::ShutdownRequest(_) => "shutdown_request",
468 JupyterMessageContent::Status(_) => "status",
469 JupyterMessageContent::StreamContent(_) => "stream",
470 JupyterMessageContent::UnknownMessage(unk) => unk.msg_type.as_str(),
471 JupyterMessageContent::UpdateDisplayData(_) => "update_display_data",
472 }
473 }
474
475 pub fn from_type_and_content(msg_type: &str, content: Value) -> serde_json::Result<Self> {
476 match msg_type {
477 "clear_output" => Ok(JupyterMessageContent::ClearOutput(serde_json::from_value(
478 content,
479 )?)),
480
481 "comm_close" => Ok(JupyterMessageContent::CommClose(serde_json::from_value(
482 content,
483 )?)),
484
485 "comm_info_reply" => Ok(JupyterMessageContent::CommInfoReply(
486 serde_json::from_value(content)?,
487 )),
488 "comm_info_request" => Ok(JupyterMessageContent::CommInfoRequest(
489 serde_json::from_value(content)?,
490 )),
491
492 "comm_msg" => Ok(JupyterMessageContent::CommMsg(serde_json::from_value(
493 content,
494 )?)),
495 "comm_open" => Ok(JupyterMessageContent::CommOpen(serde_json::from_value(
496 content,
497 )?)),
498
499 "complete_reply" => Ok(JupyterMessageContent::CompleteReply(
500 serde_json::from_value(content)?,
501 )),
502 "complete_request" => Ok(JupyterMessageContent::CompleteRequest(
503 serde_json::from_value(content)?,
504 )),
505
506 "debug_reply" => Ok(JupyterMessageContent::DebugReply(serde_json::from_value(
507 content,
508 )?)),
509 "debug_request" => Ok(JupyterMessageContent::DebugRequest(serde_json::from_value(
510 content,
511 )?)),
512
513 "display_data" => Ok(JupyterMessageContent::DisplayData(serde_json::from_value(
514 content,
515 )?)),
516
517 "error" => Ok(JupyterMessageContent::ErrorOutput(serde_json::from_value(
518 content,
519 )?)),
520
521 "execute_input" => Ok(JupyterMessageContent::ExecuteInput(serde_json::from_value(
522 content,
523 )?)),
524
525 "execute_reply" => Ok(JupyterMessageContent::ExecuteReply(serde_json::from_value(
526 content,
527 )?)),
528 "execute_request" => Ok(JupyterMessageContent::ExecuteRequest(
529 serde_json::from_value(content)?,
530 )),
531
532 "execute_result" => Ok(JupyterMessageContent::ExecuteResult(
533 serde_json::from_value(content)?,
534 )),
535
536 "history_reply" => Ok(JupyterMessageContent::HistoryReply(serde_json::from_value(
537 content,
538 )?)),
539 "history_request" => Ok(JupyterMessageContent::HistoryRequest(
540 serde_json::from_value(content)?,
541 )),
542
543 "input_reply" => Ok(JupyterMessageContent::InputReply(serde_json::from_value(
544 content,
545 )?)),
546 "input_request" => Ok(JupyterMessageContent::InputRequest(serde_json::from_value(
547 content,
548 )?)),
549
550 "inspect_reply" => Ok(JupyterMessageContent::InspectReply(serde_json::from_value(
551 content,
552 )?)),
553 "inspect_request" => Ok(JupyterMessageContent::InspectRequest(
554 serde_json::from_value(content)?,
555 )),
556
557 "interrupt_reply" => Ok(JupyterMessageContent::InterruptReply(
558 serde_json::from_value(content)?,
559 )),
560 "interrupt_request" => Ok(JupyterMessageContent::InterruptRequest(
561 serde_json::from_value(content)?,
562 )),
563
564 "iopub_welcome" => Ok(JupyterMessageContent::IoPubWelcome(serde_json::from_value(
565 content,
566 )?)),
567
568 "is_complete_reply" => Ok(JupyterMessageContent::IsCompleteReply(
569 serde_json::from_value(content)?,
570 )),
571 "is_complete_request" => Ok(JupyterMessageContent::IsCompleteRequest(
572 serde_json::from_value(content)?,
573 )),
574
575 "kernel_info_reply" => Ok(JupyterMessageContent::KernelInfoReply(
576 serde_json::from_value(content)?,
577 )),
578 "kernel_info_request" => Ok(JupyterMessageContent::KernelInfoRequest(
579 serde_json::from_value(content)?,
580 )),
581
582 "shutdown_reply" => Ok(JupyterMessageContent::ShutdownReply(
583 serde_json::from_value(content)?,
584 )),
585 "shutdown_request" => Ok(JupyterMessageContent::ShutdownRequest(
586 serde_json::from_value(content)?,
587 )),
588
589 "status" => Ok(JupyterMessageContent::Status(serde_json::from_value(
590 content,
591 )?)),
592
593 "stream" => Ok(JupyterMessageContent::StreamContent(
594 serde_json::from_value(content)?,
595 )),
596
597 "update_display_data" => Ok(JupyterMessageContent::UpdateDisplayData(
598 serde_json::from_value(content)?,
599 )),
600
601 _ => Ok(JupyterMessageContent::UnknownMessage(UnknownMessage {
602 msg_type: msg_type.to_string(),
603 content,
604 })),
605 }
606 }
607}
608
609macro_rules! impl_message_traits {
610 ($($name:ident),*) => {
611 $(
612 impl $name {
613 #[doc = concat!("Create a new `JupyterMessage`, assigning the parent for a `", stringify!($name), "` message.\n")]
614 #[doc = concat!("use jupyter_protocol::", stringify!($name), ";\n")]
622 #[doc = concat!("let child_message = ", stringify!($name), "{\n")]
629 #[must_use]
636 pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
637 JupyterMessage::new(self.clone(), Some(parent))
638 }
639 }
640
641 impl From<$name> for JupyterMessage {
642 #[doc(hidden)]
643 #[doc = concat!("Create a new `JupyterMessage` for a `", stringify!($name), "`.\n\n")]
644 fn from(content: $name) -> Self {
647 JupyterMessage::new(content, None)
648 }
649 }
650
651 impl From<$name> for JupyterMessageContent {
652 #[doc = concat!("Create a new `JupyterMessageContent` for a `", stringify!($name), "`.\n\n")]
653 fn from(content: $name) -> Self {
654 JupyterMessageContent::$name(content)
655 }
656 }
657 )*
658 };
659}
660
661impl From<JupyterMessageContent> for JupyterMessage {
662 fn from(content: JupyterMessageContent) -> Self {
663 JupyterMessage::new(content, None)
664 }
665}
666
667impl_message_traits!(
668 ClearOutput,
669 CommClose,
670 CommInfoReply,
671 CommInfoRequest,
672 CommMsg,
673 CommOpen,
674 CompleteReply,
675 CompleteRequest,
676 DebugReply,
677 DebugRequest,
678 DisplayData,
679 ErrorOutput,
680 ExecuteInput,
681 ExecuteReply,
682 ExecuteRequest,
683 ExecuteResult,
684 HistoryReply,
685 InputReply,
687 InputRequest,
688 InspectReply,
689 InspectRequest,
690 InterruptReply,
691 InterruptRequest,
692 IoPubWelcome,
693 IsCompleteReply,
694 IsCompleteRequest,
695 KernelInfoRequest,
697 ShutdownReply,
698 ShutdownRequest,
699 Status,
700 StreamContent,
701 UpdateDisplayData,
702 UnknownMessage
703);
704
705impl KernelInfoReply {
707 pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
708 JupyterMessage::new(
709 JupyterMessageContent::KernelInfoReply(Box::new(self.clone())),
710 Some(parent),
711 )
712 }
713}
714
715impl From<KernelInfoReply> for JupyterMessage {
716 fn from(content: KernelInfoReply) -> Self {
717 JupyterMessage::new(
718 JupyterMessageContent::KernelInfoReply(Box::new(content)),
719 None,
720 )
721 }
722}
723
724impl From<KernelInfoReply> for JupyterMessageContent {
725 fn from(content: KernelInfoReply) -> Self {
726 JupyterMessageContent::KernelInfoReply(Box::new(content))
727 }
728}
729
730impl HistoryRequest {
731 #[must_use]
757 pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
758 JupyterMessage::new(self.clone(), Some(parent))
759 }
760}
761
762impl From<HistoryRequest> for JupyterMessage {
763 #[doc(hidden)]
764 fn from(content: HistoryRequest) -> Self {
768 JupyterMessage::new(content, None)
769 }
770}
771
772impl From<HistoryRequest> for JupyterMessageContent {
773 fn from(content: HistoryRequest) -> Self {
775 JupyterMessageContent::HistoryRequest(content)
776 }
777}
778
779#[derive(Serialize, Deserialize, Debug, Clone)]
794pub struct UnknownMessage {
795 #[serde(skip_serializing, skip_deserializing)]
796 pub msg_type: String,
797 #[serde(flatten)]
798 pub content: Value,
799}
800impl Default for UnknownMessage {
801 fn default() -> Self {
802 Self {
803 msg_type: "unknown".to_string(),
804 content: Value::Null,
805 }
806 }
807}
808
809impl UnknownMessage {
810 pub fn reply(&self, content: serde_json::Value) -> JupyterMessageContent {
814 JupyterMessageContent::UnknownMessage(UnknownMessage {
815 msg_type: self.msg_type.replace("_request", "_reply"),
816 content,
817 })
818 }
819}
820
821#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
823#[serde(rename_all = "lowercase")]
824pub enum ReplyStatus {
825 #[default]
826 Ok,
827 Error,
828 Aborted,
829}
830
831#[derive(Serialize, Deserialize, Debug, Clone, Default)]
832pub struct ReplyError {
833 pub ename: String,
834 pub evalue: String,
835 pub traceback: Vec<String>,
836}
837
838#[derive(Serialize, Deserialize, Debug, Clone, Default)]
840pub struct ClearOutput {
841 pub wait: bool,
845}
846
847#[derive(Serialize, Deserialize, Debug, Clone)]
851pub struct ExecuteRequest {
852 pub code: String,
853 pub silent: bool,
854 pub store_history: bool,
855 #[serde(serialize_with = "serialize_user_expressions")]
856 pub user_expressions: Option<HashMap<String, String>>,
857 #[serde(default = "default_allow_stdin")]
858 pub allow_stdin: bool,
859 #[serde(default = "default_stop_on_error")]
860 pub stop_on_error: bool,
861}
862
863fn serialize_user_expressions<S>(
867 user_expressions: &Option<HashMap<String, String>>,
868 serializer: S,
869) -> Result<S::Ok, S::Error>
870where
871 S: serde::Serializer,
872{
873 match user_expressions {
874 Some(user_expressions) => user_expressions.serialize(serializer),
875 None => serde_json::Map::new().serialize(serializer),
876 }
877}
878
879fn default_allow_stdin() -> bool {
880 false
881}
882
883fn default_stop_on_error() -> bool {
884 true
885}
886
887impl ExecuteRequest {
888 pub fn new(code: String) -> Self {
889 Self {
890 code,
891 ..Default::default()
892 }
893 }
894}
895
896impl Default for ExecuteRequest {
897 fn default() -> Self {
898 Self {
899 code: "".to_string(),
900 silent: false,
901 store_history: true,
902 user_expressions: None,
903 allow_stdin: false,
904 stop_on_error: true,
905 }
906 }
907}
908
909#[derive(Serialize, Deserialize, Debug, Clone)]
917pub struct ExecuteReply {
918 #[serde(default)]
919 pub status: ReplyStatus,
920 pub execution_count: ExecutionCount,
921
922 #[serde(default)]
923 pub payload: Vec<Payload>,
924 pub user_expressions: Option<HashMap<String, String>>,
925
926 #[serde(flatten, skip_serializing_if = "Option::is_none")]
927 pub error: Option<Box<ReplyError>>,
928}
929impl Default for ExecuteReply {
930 fn default() -> Self {
931 Self {
932 status: ReplyStatus::Ok,
933 execution_count: ExecutionCount::new(0),
934 payload: Vec::new(),
935 user_expressions: None,
936 error: None,
937 }
938 }
939}
940
941#[derive(Serialize, Deserialize, Debug, Clone)]
946#[serde(rename_all = "snake_case")]
947#[serde(tag = "source")]
948pub enum Payload {
949 Page {
950 data: Media,
951 start: usize,
952 },
953 SetNextInput {
954 text: String,
955 replace: bool,
956 },
957 EditMagic {
958 filename: String,
959 line_number: usize,
960 },
961 AskExit {
962 keepkernel: bool,
964 },
965}
966
967#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
971pub struct KernelInfoRequest {}
972
973#[derive(Serialize, Deserialize, Debug, Clone)]
977pub struct KernelInfoReply {
978 pub status: ReplyStatus,
979 pub protocol_version: String,
980 pub implementation: String,
981 pub implementation_version: String,
982 pub language_info: LanguageInfo,
983 pub banner: String,
984 pub help_links: Vec<HelpLink>,
985 #[serde(default = "default_debugger")]
986 pub debugger: bool,
987 #[serde(flatten, skip_serializing_if = "Option::is_none")]
988 pub error: Option<Box<ReplyError>>,
989}
990
991fn default_debugger() -> bool {
992 false
993}
994
995#[derive(Serialize, Deserialize, Debug, Clone)]
996#[serde(untagged)]
997pub enum CodeMirrorMode {
998 Simple(String),
999 CustomMode { name: String, version: usize },
1000}
1001
1002#[derive(Serialize, Deserialize, Debug, Clone)]
1003pub struct CodeMirrorModeObject {
1004 pub name: String,
1005 pub version: usize,
1006}
1007
1008impl CodeMirrorMode {
1009 pub fn typescript() -> Self {
1010 Self::Simple("typescript".to_string())
1011 }
1012
1013 pub fn python() -> Self {
1014 Self::Simple("python".to_string())
1015 }
1016
1017 pub fn ipython_code_mirror_mode() -> Self {
1018 Self::CustomMode {
1019 name: "ipython".to_string(),
1020 version: 3,
1021 }
1022 }
1023}
1024
1025#[derive(Serialize, Deserialize, Debug, Clone)]
1026pub struct LanguageInfo {
1027 pub name: String,
1028 pub version: String,
1029 #[serde(skip_serializing_if = "Option::is_none")]
1030 pub mimetype: Option<String>,
1031 #[serde(skip_serializing_if = "Option::is_none")]
1032 pub file_extension: Option<String>,
1033 #[serde(skip_serializing_if = "Option::is_none")]
1034 pub pygments_lexer: Option<String>,
1035 #[serde(skip_serializing_if = "Option::is_none")]
1036 pub codemirror_mode: Option<CodeMirrorMode>,
1037 #[serde(skip_serializing_if = "Option::is_none")]
1038 pub nbconvert_exporter: Option<String>,
1039}
1040
1041#[derive(Serialize, Deserialize, Debug, Clone)]
1042pub struct HelpLink {
1043 pub text: String,
1044 pub url: String,
1045}
1046
1047#[derive(Serialize, Deserialize, Debug, Clone)]
1048pub enum Stdio {
1049 #[serde(rename = "stdout")]
1050 Stdout,
1051 #[serde(rename = "stderr")]
1052 Stderr,
1053}
1054
1055#[derive(Serialize, Deserialize, Debug, Clone)]
1097pub struct StreamContent {
1098 pub name: Stdio,
1099 pub text: String,
1100}
1101impl Default for StreamContent {
1102 fn default() -> Self {
1103 Self {
1104 name: Stdio::Stdout,
1105 text: String::new(),
1106 }
1107 }
1108}
1109
1110impl StreamContent {
1111 pub fn stdout(text: &str) -> Self {
1112 Self {
1113 name: Stdio::Stdout,
1114 text: text.to_string(),
1115 }
1116 }
1117
1118 pub fn stderr(text: &str) -> Self {
1119 Self {
1120 name: Stdio::Stderr,
1121 text: text.to_string(),
1122 }
1123 }
1124}
1125
1126#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1128pub struct Transient {
1129 #[serde(skip_serializing_if = "Option::is_none")]
1130 pub display_id: Option<String>,
1131}
1132
1133#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1173pub struct DisplayData {
1174 pub data: Media,
1175 pub metadata: serde_json::Map<String, Value>,
1176 #[serde(default, skip_serializing_if = "Option::is_none")]
1177 pub transient: Option<Transient>,
1178}
1179
1180impl DisplayData {
1181 pub fn new(data: Media) -> Self {
1182 Self {
1183 data,
1184 metadata: Default::default(),
1185 transient: Default::default(),
1186 }
1187 }
1188}
1189
1190impl From<Vec<MediaType>> for DisplayData {
1191 fn from(content: Vec<MediaType>) -> Self {
1192 Self::new(Media::new(content))
1193 }
1194}
1195
1196impl From<MediaType> for DisplayData {
1197 fn from(content: MediaType) -> Self {
1198 Self::new(Media::new(vec![content]))
1199 }
1200}
1201
1202#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1205pub struct UpdateDisplayData {
1206 pub data: Media,
1207 #[serde(default)]
1208 pub metadata: serde_json::Map<String, Value>,
1209 pub transient: Transient,
1210}
1211
1212impl UpdateDisplayData {
1213 pub fn new(data: Media, display_id: &str) -> Self {
1214 Self {
1215 data,
1216 metadata: Default::default(),
1217 transient: Transient {
1218 display_id: Some(display_id.to_string()),
1219 },
1220 }
1221 }
1222}
1223
1224#[derive(Serialize, Deserialize, Debug, Clone)]
1230pub struct ExecuteInput {
1231 pub code: String,
1232 pub execution_count: ExecutionCount,
1233}
1234impl Default for ExecuteInput {
1235 fn default() -> Self {
1236 Self {
1237 code: String::new(),
1238 execution_count: ExecutionCount::new(0),
1239 }
1240 }
1241}
1242
1243#[derive(Serialize, Deserialize, Debug, Clone)]
1267pub struct ExecuteResult {
1268 pub execution_count: ExecutionCount,
1269 pub data: Media,
1270 #[serde(default)]
1271 pub metadata: serde_json::Map<String, Value>,
1272 pub transient: Option<Transient>,
1273}
1274impl Default for ExecuteResult {
1275 fn default() -> Self {
1276 Self {
1277 execution_count: ExecutionCount::new(0),
1278 data: Media::default(),
1279 metadata: serde_json::Map::new(),
1280 transient: None,
1281 }
1282 }
1283}
1284
1285impl ExecuteResult {
1286 pub fn new(execution_count: ExecutionCount, data: Media) -> Self {
1287 Self {
1288 execution_count,
1289 data,
1290 metadata: Default::default(),
1291 transient: None,
1292 }
1293 }
1294}
1295
1296impl From<(ExecutionCount, Vec<MediaType>)> for ExecuteResult {
1297 fn from((execution_count, content): (ExecutionCount, Vec<MediaType>)) -> Self {
1298 Self::new(execution_count, content.into())
1299 }
1300}
1301
1302impl From<(ExecutionCount, MediaType)> for ExecuteResult {
1303 fn from((execution_count, content): (ExecutionCount, MediaType)) -> Self {
1304 Self::new(execution_count, content.into())
1305 }
1306}
1307
1308#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1314pub struct ErrorOutput {
1315 pub ename: String,
1316 pub evalue: String,
1317 pub traceback: Vec<String>,
1318}
1319
1320#[derive(Serialize, Deserialize, Debug, Clone)]
1348pub struct CommOpen {
1349 pub comm_id: CommId,
1350 pub target_name: String,
1351 pub data: serde_json::Map<String, Value>,
1352 #[serde(skip_serializing_if = "Option::is_none")]
1353 pub target_module: Option<String>,
1354}
1355impl Default for CommOpen {
1356 fn default() -> Self {
1357 Self {
1358 comm_id: CommId("".to_string()),
1359 target_name: String::new(),
1360 data: serde_json::Map::new(),
1361 target_module: None,
1362 }
1363 }
1364}
1365
1366#[derive(Serialize, Deserialize, Debug, Clone)]
1385pub struct CommMsg {
1386 pub comm_id: CommId,
1387 pub data: serde_json::Map<String, Value>,
1388}
1389impl Default for CommMsg {
1390 fn default() -> Self {
1391 Self {
1392 comm_id: CommId("".to_string()),
1393 data: serde_json::Map::new(),
1394 }
1395 }
1396}
1397
1398#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1399pub struct CommInfoRequest {
1400 pub target_name: Option<String>,
1401}
1402
1403#[derive(Eq, Hash, PartialEq, Serialize, Deserialize, Debug, Clone)]
1404pub struct CommId(pub String);
1405
1406impl From<CommId> for String {
1407 fn from(comm_id: CommId) -> Self {
1408 comm_id.0
1409 }
1410}
1411
1412impl From<String> for CommId {
1413 fn from(comm_id: String) -> Self {
1414 Self(comm_id)
1415 }
1416}
1417
1418#[derive(Serialize, Deserialize, Debug, Clone)]
1419pub struct CommInfo {
1420 pub target_name: String,
1421}
1422
1423#[derive(Serialize, Deserialize, Debug, Clone)]
1424pub struct CommInfoReply {
1425 #[serde(default)]
1426 pub status: ReplyStatus,
1427 pub comms: HashMap<CommId, CommInfo>,
1428 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1430 pub error: Option<Box<ReplyError>>,
1431}
1432impl Default for CommInfoReply {
1433 fn default() -> Self {
1434 Self {
1435 status: ReplyStatus::Ok,
1436 comms: HashMap::new(),
1437 error: None,
1438 }
1439 }
1440}
1441
1442#[derive(Serialize, Deserialize, Debug, Clone)]
1447pub struct CommClose {
1448 pub comm_id: CommId,
1449 pub data: serde_json::Map<String, Value>,
1450}
1451impl Default for CommClose {
1452 fn default() -> Self {
1453 Self {
1454 comm_id: CommId("".to_string()),
1455 data: serde_json::Map::new(),
1456 }
1457 }
1458}
1459
1460#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1461pub struct ShutdownRequest {
1468 pub restart: bool,
1469}
1470
1471#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1472pub struct InterruptRequest {}
1480
1481#[derive(Serialize, Deserialize, Debug, Clone)]
1482pub struct InterruptReply {
1489 pub status: ReplyStatus,
1490
1491 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1492 pub error: Option<Box<ReplyError>>,
1493}
1494
1495impl Default for InterruptReply {
1496 fn default() -> Self {
1497 Self::new()
1498 }
1499}
1500
1501impl InterruptReply {
1502 pub fn new() -> Self {
1503 Self {
1504 status: ReplyStatus::Ok,
1505 error: None,
1506 }
1507 }
1508}
1509
1510#[derive(Serialize, Deserialize, Debug, Clone)]
1511pub struct ShutdownReply {
1518 pub restart: bool,
1519 pub status: ReplyStatus,
1520
1521 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1522 pub error: Option<Box<ReplyError>>,
1523}
1524impl Default for ShutdownReply {
1525 fn default() -> Self {
1526 Self {
1527 restart: false,
1528 status: ReplyStatus::Ok,
1529 error: None,
1530 }
1531 }
1532}
1533
1534#[derive(Serialize, Deserialize, Debug, Clone)]
1535pub struct InputRequest {
1542 pub prompt: String,
1543 pub password: bool,
1544}
1545impl Default for InputRequest {
1546 fn default() -> Self {
1547 Self {
1548 prompt: "> ".to_string(),
1549 password: false,
1550 }
1551 }
1552}
1553
1554#[derive(Serialize, Deserialize, Debug, Clone)]
1555pub struct InputReply {
1562 pub value: String,
1563
1564 pub status: ReplyStatus,
1565 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1566 pub error: Option<Box<ReplyError>>,
1567}
1568impl Default for InputReply {
1569 fn default() -> Self {
1570 Self {
1571 value: String::new(),
1572 status: ReplyStatus::Ok,
1573 error: None,
1574 }
1575 }
1576}
1577
1578#[derive(Serialize, Deserialize, Debug, Clone)]
1584pub struct InspectRequest {
1585 pub code: String,
1588 pub cursor_pos: usize,
1590 pub detail_level: Option<usize>,
1595}
1596impl Default for InspectRequest {
1597 fn default() -> Self {
1598 Self {
1599 code: String::new(),
1600 cursor_pos: 0,
1601 detail_level: Some(0),
1602 }
1603 }
1604}
1605
1606#[derive(Serialize, Deserialize, Debug, Clone)]
1607pub struct InspectReply {
1608 pub found: bool,
1609 pub data: Media,
1610 pub metadata: serde_json::Map<String, Value>,
1611 #[serde(default)]
1612 pub status: ReplyStatus,
1613 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1614 pub error: Option<Box<ReplyError>>,
1615}
1616impl Default for InspectReply {
1617 fn default() -> Self {
1618 Self {
1619 found: false,
1620 data: Media::default(),
1621 metadata: serde_json::Map::new(),
1622 status: ReplyStatus::Ok,
1623 error: None,
1624 }
1625 }
1626}
1627
1628#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1632pub struct CompleteRequest {
1633 pub code: String,
1634 pub cursor_pos: usize,
1635}
1636
1637#[derive(Serialize, Deserialize, Debug, Clone)]
1641pub struct CompleteReply {
1642 pub matches: Vec<String>,
1643 pub cursor_start: usize,
1644 pub cursor_end: usize,
1645 pub metadata: serde_json::Map<String, Value>,
1646 #[serde(default)]
1647 pub status: ReplyStatus,
1648 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1649 pub error: Option<Box<ReplyError>>,
1650}
1651impl Default for CompleteReply {
1652 fn default() -> Self {
1653 Self {
1654 matches: Vec::new(),
1655 cursor_start: 0,
1656 cursor_end: 0,
1657 metadata: serde_json::Map::new(),
1658 status: ReplyStatus::Ok,
1659 error: None,
1660 }
1661 }
1662}
1663
1664#[derive(Serialize, Deserialize, Debug, Clone)]
1665pub struct DebugRequest {
1666 #[serde(flatten)]
1667 pub content: Value,
1668}
1669impl Default for DebugRequest {
1670 fn default() -> Self {
1671 Self {
1672 content: Value::Null,
1673 }
1674 }
1675}
1676
1677#[derive(Serialize, Deserialize, Debug, Clone)]
1678pub struct DebugReply {
1679 #[serde(flatten)]
1680 pub content: Value,
1681}
1682impl Default for DebugReply {
1683 fn default() -> Self {
1684 Self {
1685 content: Value::Null,
1686 }
1687 }
1688}
1689
1690#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1691#[serde(rename_all = "snake_case")]
1692pub enum IsCompleteReplyStatus {
1693 Incomplete,
1696 Complete,
1698 Invalid,
1700 Unknown,
1705}
1706
1707#[derive(Serialize, Deserialize, Debug, Clone)]
1708pub struct IsCompleteReply {
1709 pub status: IsCompleteReplyStatus,
1712 pub indent: String,
1717}
1718impl Default for IsCompleteReply {
1719 fn default() -> Self {
1720 Self {
1721 status: IsCompleteReplyStatus::Unknown,
1722 indent: String::new(),
1723 }
1724 }
1725}
1726
1727impl IsCompleteReply {
1728 pub fn new(status: IsCompleteReplyStatus, indent: String) -> Self {
1729 Self { status, indent }
1730 }
1731
1732 pub fn incomplete(indent: String) -> Self {
1733 Self::new(IsCompleteReplyStatus::Incomplete, indent)
1734 }
1735
1736 pub fn complete() -> Self {
1737 Self::new(IsCompleteReplyStatus::Complete, String::new())
1738 }
1739
1740 pub fn invalid() -> Self {
1741 Self::new(IsCompleteReplyStatus::Invalid, String::new())
1742 }
1743
1744 pub fn unknown() -> Self {
1745 Self::new(IsCompleteReplyStatus::Unknown, String::new())
1746 }
1747}
1748
1749#[derive(Serialize, Deserialize, Debug, Clone)]
1750#[serde(tag = "hist_access_type")]
1751pub enum HistoryRequest {
1752 #[serde(rename = "range")]
1753 Range {
1754 session: Option<i32>,
1755 start: i32,
1756 stop: i32,
1757 output: bool,
1758 raw: bool,
1759 },
1760 #[serde(rename = "tail")]
1761 Tail { n: i32, output: bool, raw: bool },
1762 #[serde(rename = "search")]
1763 Search {
1764 pattern: String,
1765 unique: bool,
1766 output: bool,
1767 raw: bool,
1768 n: i32,
1769 },
1770}
1771impl Default for HistoryRequest {
1772 fn default() -> Self {
1773 Self::Range {
1774 session: None,
1775 start: 0,
1776 stop: 0,
1777 output: false,
1778 raw: false,
1779 }
1780 }
1781}
1782
1783#[derive(Serialize, Deserialize, Debug, Clone)]
1784#[serde(untagged)]
1785pub enum HistoryEntry {
1786 Input(usize, usize, String),
1789 InputOutput(usize, usize, (String, String)),
1792}
1793
1794#[derive(Serialize, Deserialize, Debug, Clone)]
1798pub struct HistoryReply {
1799 pub history: Vec<HistoryEntry>,
1800
1801 pub status: ReplyStatus,
1802 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1803 pub error: Option<Box<ReplyError>>,
1804}
1805impl Default for HistoryReply {
1806 fn default() -> Self {
1807 Self {
1808 history: Vec::new(),
1809 status: ReplyStatus::Ok,
1810 error: None,
1811 }
1812 }
1813}
1814
1815impl HistoryReply {
1816 pub fn new(history: Vec<HistoryEntry>) -> Self {
1817 Self {
1818 history,
1819 status: ReplyStatus::Ok,
1820 error: None,
1821 }
1822 }
1823}
1824
1825#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1829pub struct IsCompleteRequest {
1830 pub code: String,
1831}
1832
1833#[derive(Debug, Clone, PartialEq)]
1834pub enum ExecutionState {
1835 Unknown,
1836 Starting,
1837 Busy,
1838 Idle,
1839 Restarting,
1840 Terminating,
1841 AutoRestarting,
1842 Dead,
1843 Other(String),
1844}
1845
1846impl ExecutionState {
1847 pub fn as_str(&self) -> &str {
1848 match self {
1849 ExecutionState::Unknown => "unknown",
1850 ExecutionState::Terminating => "terminating",
1851 ExecutionState::AutoRestarting => "autorestarting",
1852 ExecutionState::Dead => "dead",
1853 ExecutionState::Busy => "busy",
1854 ExecutionState::Idle => "idle",
1855 ExecutionState::Starting => "starting",
1856 ExecutionState::Restarting => "restarting",
1857 ExecutionState::Other(s) => s,
1858 }
1859 }
1860}
1861
1862impl serde::Serialize for ExecutionState {
1863 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1864 where
1865 S: serde::Serializer,
1866 {
1867 match self {
1868 ExecutionState::Unknown => serializer.serialize_str("unknown"),
1869 ExecutionState::Terminating => serializer.serialize_str("terminating"),
1870 ExecutionState::AutoRestarting => serializer.serialize_str("autorestarting"),
1871 ExecutionState::Dead => serializer.serialize_str("dead"),
1872 ExecutionState::Busy => serializer.serialize_str("busy"),
1873 ExecutionState::Idle => serializer.serialize_str("idle"),
1874 ExecutionState::Starting => serializer.serialize_str("starting"),
1875 ExecutionState::Restarting => serializer.serialize_str("restarting"),
1876 ExecutionState::Other(s) => serializer.serialize_str(s),
1877 }
1878 }
1879}
1880
1881impl<'de> serde::Deserialize<'de> for ExecutionState {
1882 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1883 where
1884 D: serde::Deserializer<'de>,
1885 {
1886 struct ExecutionStateVisitor;
1887
1888 impl serde::de::Visitor<'_> for ExecutionStateVisitor {
1889 type Value = ExecutionState;
1890
1891 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1892 formatter.write_str("a string representing an execution state")
1893 }
1894 fn visit_str<E>(self, value: &str) -> Result<ExecutionState, E>
1895 where
1896 E: serde::de::Error,
1897 {
1898 match value {
1899 "unknown" => Ok(ExecutionState::Unknown),
1900 "terminating" => Ok(ExecutionState::Terminating),
1901 "autorestarting" => Ok(ExecutionState::AutoRestarting),
1902 "dead" => Ok(ExecutionState::Dead),
1903 "busy" => Ok(ExecutionState::Busy),
1904 "idle" => Ok(ExecutionState::Idle),
1905 "starting" => Ok(ExecutionState::Starting),
1906 "restarting" => Ok(ExecutionState::Restarting),
1907 other => Ok(ExecutionState::Other(other.to_string())),
1908 }
1909 }
1910 }
1911 deserializer.deserialize_str(ExecutionStateVisitor)
1912 }
1913}
1914
1915#[derive(Serialize, Deserialize, Debug, Clone)]
1919pub struct Status {
1920 pub execution_state: ExecutionState,
1921}
1922impl Default for Status {
1923 fn default() -> Self {
1924 Self {
1925 execution_state: ExecutionState::Idle,
1926 }
1927 }
1928}
1929
1930impl Status {
1931 pub fn busy() -> Self {
1932 Self {
1933 execution_state: ExecutionState::Busy,
1934 }
1935 }
1936
1937 pub fn idle() -> Self {
1938 Self {
1939 execution_state: ExecutionState::Idle,
1940 }
1941 }
1942
1943 pub fn starting() -> Self {
1944 Self {
1945 execution_state: ExecutionState::Starting,
1946 }
1947 }
1948
1949 pub fn restarting() -> Self {
1950 Self {
1951 execution_state: ExecutionState::Restarting,
1952 }
1953 }
1954
1955 pub fn other(state: impl Into<String>) -> Self {
1956 Self {
1957 execution_state: ExecutionState::Other(state.into()),
1958 }
1959 }
1960}
1961
1962#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1969pub struct IoPubWelcome {
1970 pub subscription: String,
1973}
1974
1975impl IoPubWelcome {
1976 pub fn new(subscription: String) -> Self {
1977 Self { subscription }
1978 }
1979}
1980
1981#[cfg(test)]
1982mod test {
1983 use serde_json::json;
1984
1985 use super::*;
1986
1987 #[test]
1988 fn test_execute_request_serialize() {
1989 let request = ExecuteRequest {
1990 code: "print('Hello, World!')".to_string(),
1991 silent: false,
1992 store_history: true,
1993 user_expressions: Some(HashMap::new()),
1994 allow_stdin: false,
1995 stop_on_error: true,
1996 };
1997 let request_value = serde_json::to_value(request).unwrap();
1998
1999 let expected_request_value = serde_json::json!({
2000 "code": "print('Hello, World!')",
2001 "silent": false,
2002 "store_history": true,
2003 "user_expressions": {},
2004 "allow_stdin": false,
2005 "stop_on_error": true
2006 });
2007
2008 assert_eq!(request_value, expected_request_value);
2009 }
2010
2011 #[test]
2012 fn test_execute_request_user_expressions_serializes_to_empty_dict() {
2013 let request = ExecuteRequest {
2014 code: "print('Hello, World!')".to_string(),
2015 silent: false,
2016 store_history: true,
2017 user_expressions: None,
2018 allow_stdin: false,
2019 stop_on_error: true,
2020 };
2021 let request_value = serde_json::to_value(request).unwrap();
2022
2023 let expected_request_value = serde_json::json!({
2024 "code": "print('Hello, World!')",
2025 "silent": false,
2026 "store_history": true,
2027 "user_expressions": {},
2028 "allow_stdin": false,
2029 "stop_on_error": true
2030 });
2031
2032 assert_eq!(request_value, expected_request_value);
2033 }
2034
2035 #[test]
2036 fn test_into_various() {
2037 let kernel_info_request = KernelInfoRequest {};
2038 let content: JupyterMessageContent = kernel_info_request.clone().into();
2039 let message: JupyterMessage = content.into();
2040 assert!(message.parent_header.is_none());
2041 match message.content {
2042 JupyterMessageContent::KernelInfoRequest(req) => {
2043 assert_eq!(req, kernel_info_request);
2044 }
2045 _ => panic!("Expected KernelInfoRequest"),
2046 }
2047
2048 let kernel_info_request = KernelInfoRequest {};
2049 let message: JupyterMessage = kernel_info_request.clone().into();
2050 assert!(message.parent_header.is_none());
2051 match message.content {
2052 JupyterMessageContent::KernelInfoRequest(req) => {
2053 assert_eq!(req, kernel_info_request);
2054 }
2055 _ => panic!("Expected KernelInfoRequest"),
2056 }
2057 }
2058
2059 #[test]
2060 fn test_default() {
2061 let msg: JupyterMessage = ExecuteRequest {
2062 code: "import this".to_string(),
2063 ..Default::default()
2064 }
2065 .into();
2066
2067 assert_eq!(msg.header.msg_type, "execute_request");
2068 assert_eq!(msg.header.msg_id.len(), 36);
2069
2070 match msg.content {
2071 JupyterMessageContent::ExecuteRequest(req) => {
2072 assert_eq!(req.code, "import this");
2073 assert!(!req.silent);
2074 assert!(req.store_history);
2075 assert_eq!(req.user_expressions, None);
2076 assert!(!req.allow_stdin);
2077 assert!(req.stop_on_error);
2078 }
2079 _ => panic!("Expected ExecuteRequest"),
2080 }
2081 }
2082
2083 #[test]
2084 fn test_deserialize_payload() {
2085 let raw_execute_reply_content = r#"
2086 {
2087 "status": "ok",
2088 "execution_count": 1,
2089 "payload": [{
2090 "source": "page",
2091 "data": {
2092 "text/html": "<h1>Hello</h1>",
2093 "text/plain": "Hello"
2094 },
2095 "start": 0
2096 }],
2097 "user_expressions": {}
2098 }
2099 "#;
2100
2101 let execute_reply: ExecuteReply = serde_json::from_str(raw_execute_reply_content).unwrap();
2102
2103 assert_eq!(execute_reply.status, ReplyStatus::Ok);
2104 assert_eq!(execute_reply.execution_count, ExecutionCount::new(1));
2105
2106 let payload = execute_reply.payload.clone();
2107
2108 assert_eq!(payload.len(), 1);
2109 let payload = payload.first().unwrap();
2110
2111 let media = match payload {
2112 Payload::Page { data, .. } => data,
2113 _ => panic!("Expected Page payload type"),
2114 };
2115
2116 let media = serde_json::to_value(media).unwrap();
2117
2118 let expected_media = serde_json::json!({
2119 "text/html": "<h1>Hello</h1>",
2120 "text/plain": "Hello"
2121 });
2122
2123 assert_eq!(media, expected_media);
2124 }
2125
2126 #[test]
2127 pub fn test_display_data_various_data() {
2128 let display_data = DisplayData {
2129 data: serde_json::from_value(json!({
2130 "text/plain": "Hello, World!",
2131 "text/html": "<h1>Hello, World!</h1>",
2132 "application/json": {
2133 "hello": "world",
2134 "foo": "bar",
2135 "ok": [1, 2, 3],
2136 }
2137 }))
2138 .unwrap(),
2139 ..Default::default()
2140 };
2141
2142 let display_data_value = serde_json::to_value(display_data).unwrap();
2143
2144 let expected_display_data_value = serde_json::json!({
2145 "data": {
2146 "text/plain": "Hello, World!",
2147 "text/html": "<h1>Hello, World!</h1>",
2148 "application/json": {
2149 "hello": "world",
2150 "foo": "bar",
2151 "ok": [1, 2, 3]
2152 }
2153 },
2154 "metadata": {}
2155 });
2156
2157 assert_eq!(display_data_value, expected_display_data_value);
2158 }
2159
2160 use std::mem::size_of;
2161
2162 macro_rules! size_of_variant {
2163 ($variant:ty) => {
2164 let size = size_of::<$variant>();
2165 println!("The size of {} is: {} bytes", stringify!($variant), size);
2166
2167 assert!(size <= 96);
2168 };
2169 }
2170
2171 #[test]
2172 fn test_enum_variant_sizes() {
2173 size_of_variant!(ClearOutput);
2174 size_of_variant!(CommClose);
2175 size_of_variant!(CommInfoReply);
2176 size_of_variant!(CommInfoRequest);
2177 size_of_variant!(CommMsg);
2178 size_of_variant!(CommOpen);
2179 size_of_variant!(CompleteReply);
2180 size_of_variant!(CompleteRequest);
2181 size_of_variant!(DebugReply);
2182 size_of_variant!(DebugRequest);
2183 size_of_variant!(DisplayData);
2184 size_of_variant!(ErrorOutput);
2185 size_of_variant!(ExecuteInput);
2186 size_of_variant!(ExecuteReply);
2187 size_of_variant!(ExecuteRequest);
2188 size_of_variant!(ExecuteResult);
2189 size_of_variant!(HistoryReply);
2190 size_of_variant!(HistoryRequest);
2191 size_of_variant!(InputReply);
2192 size_of_variant!(InputRequest);
2193 size_of_variant!(InspectReply);
2194 size_of_variant!(InspectRequest);
2195 size_of_variant!(InterruptReply);
2196 size_of_variant!(InterruptRequest);
2197 size_of_variant!(IsCompleteReply);
2198 size_of_variant!(IsCompleteRequest);
2199 size_of_variant!(Box<KernelInfoReply>);
2200 size_of_variant!(KernelInfoRequest);
2201 size_of_variant!(ShutdownReply);
2202 size_of_variant!(ShutdownRequest);
2203 size_of_variant!(Status);
2204 size_of_variant!(StreamContent);
2205 size_of_variant!(UnknownMessage);
2206 size_of_variant!(UpdateDisplayData);
2207 }
2208
2209 #[test]
2210 fn test_jupyter_message_content_enum_size() {
2211 let size = size_of::<JupyterMessageContent>();
2212 println!("The size of JupyterMessageContent is: {}", size);
2213 assert!(size > 0);
2214 assert!(size <= 104);
2215 }
2216
2217 #[test]
2218 fn test_jupyter_message_parent_header_serializes_to_empty_dict() {
2219 let request = ExecuteRequest {
2220 code: "1 + 1".to_string(),
2221 ..Default::default()
2222 };
2223 let message = JupyterMessage::from(request);
2224
2225 let serialized_message = serde_json::to_value(message).unwrap();
2226
2227 let parent_header = serialized_message.get("parent_header").unwrap();
2229 assert!(parent_header.is_object());
2230 assert!(parent_header.as_object().unwrap().is_empty());
2231 }
2232
2233 #[test]
2234 fn test_user_expressions_serialization() {
2235 let request = ExecuteRequest {
2236 code: "pass".to_string(),
2237 silent: false,
2238 store_history: true,
2239 user_expressions: Some(HashMap::from([(
2240 String::from("expression"),
2241 String::from("42 + 7"),
2242 )])),
2243 allow_stdin: false,
2244 stop_on_error: true,
2245 };
2246 let request_value = serde_json::to_value(request.clone()).unwrap();
2247
2248 let expected_request_value = serde_json::json!({
2249 "code": "pass",
2250 "silent": false,
2251 "store_history": true,
2252 "user_expressions": {"expression": "42 + 7"},
2253 "allow_stdin": false,
2254 "stop_on_error": true
2255 });
2256
2257 assert_eq!(request_value, expected_request_value);
2258
2259 let deserialized_request: ExecuteRequest = serde_json::from_value(request_value).unwrap();
2260 assert_eq!(
2261 deserialized_request.user_expressions,
2262 request.user_expressions
2263 );
2264 }
2265
2266 #[test]
2267 fn test_jupyter_message_parent_header_deserialize() {
2268 let msg = r#"
2269 {
2270 "buffers": [],
2271 "channel": "shell",
2272 "content": {},
2273 "header": {
2274 "date": "2025-05-14T14:32:23.490Z",
2275 "msg_id": "44bd6b44-78a1-4892-87df-c0861a005d56",
2276 "msg_type": "kernel_info_request",
2277 "session": "b75bddaa-6d69-4340-ba13-81516192370e",
2278 "username": "",
2279 "version": "5.2"
2280 },
2281 "metadata": {},
2282 "parent_header": {
2283 "date": "2025-05-14T14:32:23.490Z",
2284 "msg_id": "2aaf8916-6b83-4f5a-80dd-633e94f5d8e1",
2285 "msg_type": "kernel_info_request",
2286 "session": "e2a3165d-76a8-4fef-850f-712102589660",
2287 "username": "",
2288 "version": "5.2"
2289 }
2290}
2291 "#;
2292
2293 let message: JupyterMessage = serde_json::from_str(msg).unwrap();
2294 assert!(message.parent_header.is_some());
2295 assert_eq!(
2296 message.parent_header.as_ref().unwrap().msg_type,
2297 "kernel_info_request"
2298 );
2299 assert_eq!(
2300 message.parent_header.as_ref().unwrap().msg_id,
2301 "2aaf8916-6b83-4f5a-80dd-633e94f5d8e1"
2302 );
2303 assert_eq!(
2304 message.header.msg_id,
2305 "44bd6b44-78a1-4892-87df-c0861a005d56"
2306 );
2307 }
2308
2309 #[test]
2310 fn test_jupyter_message_empty_parent_header_deserialize() {
2311 let msg = r#"
2312 {
2313 "buffers": [],
2314 "channel": "shell",
2315 "content": {},
2316 "header": {
2317 "date": "2025-05-14T14:32:23.490Z",
2318 "msg_id": "44bd6b44-78a1-4892-87df-c0861a005d56",
2319 "msg_type": "kernel_info_request",
2320 "session": "b75bddaa-6d69-4340-ba13-81516192370e",
2321 "username": "",
2322 "version": "5.2"
2323 },
2324 "metadata": {},
2325 "parent_header": {}
2326}
2327 "#;
2328
2329 let message: JupyterMessage = serde_json::from_str(msg).unwrap();
2330 assert!(message.parent_header.is_none());
2331 assert_eq!(message.header.msg_type, "kernel_info_request");
2332 assert_eq!(
2333 message.header.msg_id,
2334 "44bd6b44-78a1-4892-87df-c0861a005d56"
2335 );
2336 }
2337
2338 #[test]
2339 fn test_execution_state_other_serde() {
2340 let json = r#""busy""#;
2341 let state: ExecutionState = serde_json::from_str(json).unwrap();
2342 assert_eq!(state, ExecutionState::Busy);
2343 let serialized = serde_json::to_string(&state).unwrap();
2344 assert_eq!(serialized, "\"busy\"");
2345
2346 let state = ExecutionState::Idle;
2347 let serialized = serde_json::to_string(&state).unwrap();
2348 assert_eq!(serialized, "\"idle\"");
2349 let state: ExecutionState = serde_json::from_str(&serialized).unwrap();
2350 assert_eq!(state, ExecutionState::Idle);
2351
2352 let json = r#""disconnected""#;
2353 let state: ExecutionState = serde_json::from_str(json).unwrap();
2354 assert_eq!(state, ExecutionState::Other("disconnected".to_string()));
2355 let serialized = serde_json::to_string(&state).unwrap();
2356 assert_eq!(serialized, "\"disconnected\"");
2357 }
2358
2359 #[test]
2360 fn test_iopub_welcome_message() {
2361 let welcome = IoPubWelcome::new("".to_string());
2363 assert_eq!(welcome.subscription, "");
2364
2365 let welcome_value = serde_json::to_value(&welcome).unwrap();
2367 let expected_value = serde_json::json!({
2368 "subscription": ""
2369 });
2370 assert_eq!(welcome_value, expected_value);
2371
2372 let json_str = r#"{"subscription": ""}"#;
2374 let deserialized: IoPubWelcome = serde_json::from_str(json_str).unwrap();
2375 assert_eq!(deserialized.subscription, "");
2376
2377 let welcome_with_topic = IoPubWelcome::new("kernel.output".to_string());
2379 assert_eq!(welcome_with_topic.subscription, "kernel.output");
2380
2381 let message: JupyterMessage = welcome.clone().into();
2383 assert_eq!(message.header.msg_type, "iopub_welcome");
2384 match message.content {
2385 JupyterMessageContent::IoPubWelcome(w) => {
2386 assert_eq!(w.subscription, "");
2387 }
2388 _ => panic!("Expected IoPubWelcome"),
2389 }
2390
2391 let content_value = serde_json::json!({"subscription": "test_topic"});
2393 let content =
2394 JupyterMessageContent::from_type_and_content("iopub_welcome", content_value).unwrap();
2395 match content {
2396 JupyterMessageContent::IoPubWelcome(w) => {
2397 assert_eq!(w.subscription, "test_topic");
2398 }
2399 _ => panic!("Expected IoPubWelcome"),
2400 }
2401 }
2402}