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 #[serde(
107 serialize_with = "serialize_parent_header",
108 deserialize_with = "deserialize_parent_header"
109 )]
110 pub parent_header: Option<Header>,
111 pub metadata: Value,
112 pub content: Value,
113 #[serde(skip_serializing, skip_deserializing)]
114 pub buffers: Vec<Bytes>,
115 pub channel: Option<Channel>,
116}
117
118#[derive(Serialize, Deserialize, Debug, Clone)]
148pub struct Header {
149 pub msg_id: String,
150 pub username: String,
151 pub session: String,
152 #[serde(default, deserialize_with = "deserialize_date_with_default")]
156 pub date: DateTime<Utc>,
157 pub msg_type: String,
158 pub version: String,
159}
160
161fn serialize_parent_header<S>(
169 parent_header: &Option<Header>,
170 serializer: S,
171) -> Result<S::Ok, S::Error>
172where
173 S: serde::Serializer,
174{
175 match parent_header {
176 Some(parent_header) => parent_header.serialize(serializer),
177 None => serde_json::Map::new().serialize(serializer),
178 }
179}
180
181pub fn deserialize_parent_header<'de, D>(deserializer: D) -> Result<Option<Header>, D::Error>
187where
188 D: serde::Deserializer<'de>,
189{
190 use serde::de::Error;
191 let value = Value::deserialize(deserializer)?;
192 if value.is_null() {
193 Ok(None)
194 } else if let Some(obj) = value.as_object() {
195 if obj.is_empty() {
196 Ok(None)
197 } else {
198 serde_json::from_value(Value::Object(obj.clone()))
200 .map(Some)
201 .map_err(D::Error::custom)
202 }
203 } else {
204 serde_json::from_value(value)
206 .map(Some)
207 .map_err(D::Error::custom)
208 }
209}
210
211fn deserialize_date_with_default<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
219where
220 D: serde::Deserializer<'de>,
221{
222 let opt = Option::<DateTime<Utc>>::deserialize(deserializer)?;
223 Ok(opt.unwrap_or_else(|| DateTime::<Utc>::from_timestamp(0, 0).expect("UNIX_EPOCH is valid")))
224}
225
226#[derive(Serialize, Clone)]
275pub struct JupyterMessage {
276 #[serde(skip_serializing, skip_deserializing)]
277 pub zmq_identities: Vec<Bytes>,
278 pub header: Header,
279 #[serde(
280 serialize_with = "serialize_parent_header",
281 deserialize_with = "deserialize_parent_header"
282 )]
283 pub parent_header: Option<Header>,
284 pub metadata: Value,
285 pub content: JupyterMessageContent,
286 #[serde(skip_serializing, skip_deserializing)]
287 pub buffers: Vec<Bytes>,
288 pub channel: Option<Channel>,
289}
290
291impl JupyterMessage {
292 pub fn new(
293 content: impl Into<JupyterMessageContent>,
294 parent: Option<&JupyterMessage>,
295 ) -> JupyterMessage {
296 let session = match parent {
300 Some(parent) => parent.header.session.clone(),
301 None => Uuid::new_v4().to_string(),
302 };
303
304 let content = content.into();
305
306 let header = Header {
307 msg_id: Uuid::new_v4().to_string(),
308 username: "runtimelib".to_string(),
309 session,
310 date: time::utc_now(),
311 msg_type: content.message_type().to_owned(),
312 version: "5.3".to_string(),
313 };
314
315 JupyterMessage {
316 zmq_identities: parent.map_or(Vec::new(), |parent| parent.zmq_identities.clone()),
317 header,
318 parent_header: parent.map(|parent| parent.header.clone()),
319 metadata: json!({}),
320 content,
321 buffers: Vec::new(),
322 channel: None,
323 }
324 }
325
326 pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
327 self.metadata = metadata;
328 self
329 }
330
331 pub fn with_buffers(mut self, buffers: Vec<Bytes>) -> Self {
332 self.buffers = buffers;
333 self
334 }
335
336 pub fn with_parent(mut self, parent: &JupyterMessage) -> Self {
337 self.header.session.clone_from(&parent.header.session);
338 self.parent_header = Some(parent.header.clone());
339 self.zmq_identities.clone_from(&parent.zmq_identities);
340 self
341 }
342
343 pub fn with_zmq_identities(mut self, zmq_identities: Vec<Bytes>) -> Self {
344 self.zmq_identities = zmq_identities;
345 self
346 }
347
348 pub fn with_channel(mut self, channel: Channel) -> Self {
357 self.channel = Some(channel);
358 self
359 }
360
361 pub fn with_session(mut self, session: &str) -> Self {
362 self.header.session = session.to_string();
363 self
364 }
365
366 pub fn message_type(&self) -> &str {
367 self.content.message_type()
368 }
369
370 pub fn from_value(message: Value) -> Result<JupyterMessage, JupyterError> {
371 let message = serde_json::from_value::<UnknownJupyterMessage>(message)?;
372
373 let content =
374 JupyterMessageContent::from_type_and_content(&message.header.msg_type, message.content);
375
376 let content = match content {
377 Ok(content) => content,
378 Err(err) => {
379 return Err(JupyterError::ParseError {
380 msg_type: message.header.msg_type,
381 source: err,
382 })
383 }
384 };
385
386 let message = JupyterMessage {
387 zmq_identities: Vec::new(),
388 header: message.header,
389 parent_header: message.parent_header,
390 metadata: message.metadata,
391 content,
392 buffers: message.buffers,
393 channel: None,
394 };
395
396 Ok(message)
397 }
398}
399
400impl<'de> Deserialize<'de> for JupyterMessage {
401 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
402 where
403 D: serde::Deserializer<'de>,
404 {
405 let message = UnknownJupyterMessage::deserialize(deserializer)?;
406
407 let content =
408 JupyterMessageContent::from_type_and_content(&message.header.msg_type, message.content)
409 .map_err(serde::de::Error::custom)?;
410
411 Ok(JupyterMessage {
412 zmq_identities: Vec::new(),
413 header: message.header,
414 parent_header: message.parent_header,
415 metadata: message.metadata,
416 content,
417 buffers: message.buffers,
418 channel: message.channel,
419 })
420 }
421}
422
423impl fmt::Debug for JupyterMessage {
424 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
425 writeln!(
426 f,
427 "\nHeader: {}",
428 serde_json::to_string_pretty(&self.header).unwrap()
429 )?;
430 writeln!(
431 f,
432 "Parent header: {}",
433 if let Some(parent_header) = self.parent_header.as_ref() {
434 serde_json::to_string_pretty(parent_header).unwrap()
435 } else {
436 serde_json::to_string_pretty(&serde_json::Map::new()).unwrap()
437 }
438 )?;
439 writeln!(
440 f,
441 "Metadata: {}",
442 serde_json::to_string_pretty(&self.metadata).unwrap()
443 )?;
444 writeln!(
445 f,
446 "Content: {}\n",
447 serde_json::to_string_pretty(&self.content).unwrap()
448 )?;
449 Ok(())
450 }
451}
452
453#[derive(Serialize, Debug, Clone)]
454#[serde(untagged)]
455pub enum JupyterMessageContent {
456 ClearOutput(ClearOutput),
457 CommClose(CommClose),
458 CommInfoReply(CommInfoReply),
459 CommInfoRequest(CommInfoRequest),
460 CommMsg(CommMsg),
461 CommOpen(CommOpen),
462 CompleteReply(CompleteReply),
463 CompleteRequest(CompleteRequest),
464 DebugReply(DebugReply),
465 DebugRequest(DebugRequest),
466 DisplayData(DisplayData),
467 ErrorOutput(ErrorOutput),
468 ExecuteInput(ExecuteInput),
469 ExecuteReply(ExecuteReply),
470 ExecuteRequest(ExecuteRequest),
471 ExecuteResult(ExecuteResult),
472 HistoryReply(HistoryReply),
473 HistoryRequest(HistoryRequest),
474 InputReply(InputReply),
475 InputRequest(InputRequest),
476 InspectReply(InspectReply),
477 InspectRequest(InspectRequest),
478 InterruptReply(InterruptReply),
479 InterruptRequest(InterruptRequest),
480 IoPubWelcome(IoPubWelcome),
481 IsCompleteReply(IsCompleteReply),
482 IsCompleteRequest(IsCompleteRequest),
483 KernelInfoReply(Box<KernelInfoReply>),
486 KernelInfoRequest(KernelInfoRequest),
487 ShutdownReply(ShutdownReply),
488 ShutdownRequest(ShutdownRequest),
489 Status(Status),
490 StreamContent(StreamContent),
491 UnknownMessage(UnknownMessage),
492 UpdateDisplayData(UpdateDisplayData),
493}
494
495impl JupyterMessageContent {
496 pub fn message_type(&self) -> &str {
497 match self {
498 JupyterMessageContent::ClearOutput(_) => "clear_output",
499 JupyterMessageContent::CommClose(_) => "comm_close",
500 JupyterMessageContent::CommInfoReply(_) => "comm_info_reply",
501 JupyterMessageContent::CommInfoRequest(_) => "comm_info_request",
502 JupyterMessageContent::CommMsg(_) => "comm_msg",
503 JupyterMessageContent::CommOpen(_) => "comm_open",
504 JupyterMessageContent::CompleteReply(_) => "complete_reply",
505 JupyterMessageContent::CompleteRequest(_) => "complete_request",
506 JupyterMessageContent::DebugReply(_) => "debug_reply",
507 JupyterMessageContent::DebugRequest(_) => "debug_request",
508 JupyterMessageContent::DisplayData(_) => "display_data",
509 JupyterMessageContent::ErrorOutput(_) => "error",
510 JupyterMessageContent::ExecuteInput(_) => "execute_input",
511 JupyterMessageContent::ExecuteReply(_) => "execute_reply",
512 JupyterMessageContent::ExecuteRequest(_) => "execute_request",
513 JupyterMessageContent::ExecuteResult(_) => "execute_result",
514 JupyterMessageContent::HistoryReply(_) => "history_reply",
515 JupyterMessageContent::HistoryRequest(_) => "history_request",
516 JupyterMessageContent::InputReply(_) => "input_reply",
517 JupyterMessageContent::InputRequest(_) => "input_request",
518 JupyterMessageContent::InspectReply(_) => "inspect_reply",
519 JupyterMessageContent::InspectRequest(_) => "inspect_request",
520 JupyterMessageContent::InterruptReply(_) => "interrupt_reply",
521 JupyterMessageContent::InterruptRequest(_) => "interrupt_request",
522 JupyterMessageContent::IoPubWelcome(_) => "iopub_welcome",
523 JupyterMessageContent::IsCompleteReply(_) => "is_complete_reply",
524 JupyterMessageContent::IsCompleteRequest(_) => "is_complete_request",
525 JupyterMessageContent::KernelInfoReply(_) => "kernel_info_reply",
526 JupyterMessageContent::KernelInfoRequest(_) => "kernel_info_request",
527 JupyterMessageContent::ShutdownReply(_) => "shutdown_reply",
528 JupyterMessageContent::ShutdownRequest(_) => "shutdown_request",
529 JupyterMessageContent::Status(_) => "status",
530 JupyterMessageContent::StreamContent(_) => "stream",
531 JupyterMessageContent::UnknownMessage(unk) => unk.msg_type.as_str(),
532 JupyterMessageContent::UpdateDisplayData(_) => "update_display_data",
533 }
534 }
535
536 pub fn from_type_and_content(msg_type: &str, content: Value) -> serde_json::Result<Self> {
537 match msg_type {
538 "clear_output" => Ok(JupyterMessageContent::ClearOutput(serde_json::from_value(
539 content,
540 )?)),
541
542 "comm_close" => Ok(JupyterMessageContent::CommClose(serde_json::from_value(
543 content,
544 )?)),
545
546 "comm_info_reply" => Ok(JupyterMessageContent::CommInfoReply(
547 serde_json::from_value(content)?,
548 )),
549 "comm_info_request" => Ok(JupyterMessageContent::CommInfoRequest(
550 serde_json::from_value(content)?,
551 )),
552
553 "comm_msg" => Ok(JupyterMessageContent::CommMsg(serde_json::from_value(
554 content,
555 )?)),
556 "comm_open" => Ok(JupyterMessageContent::CommOpen(serde_json::from_value(
557 content,
558 )?)),
559
560 "complete_reply" => Ok(JupyterMessageContent::CompleteReply(
561 serde_json::from_value(content)?,
562 )),
563 "complete_request" => Ok(JupyterMessageContent::CompleteRequest(
564 serde_json::from_value(content)?,
565 )),
566
567 "debug_reply" => Ok(JupyterMessageContent::DebugReply(serde_json::from_value(
568 content,
569 )?)),
570 "debug_request" => Ok(JupyterMessageContent::DebugRequest(serde_json::from_value(
571 content,
572 )?)),
573
574 "display_data" => Ok(JupyterMessageContent::DisplayData(serde_json::from_value(
575 content,
576 )?)),
577
578 "error" => Ok(JupyterMessageContent::ErrorOutput(serde_json::from_value(
579 content,
580 )?)),
581
582 "execute_input" => Ok(JupyterMessageContent::ExecuteInput(serde_json::from_value(
583 content,
584 )?)),
585
586 "execute_reply" => Ok(JupyterMessageContent::ExecuteReply(serde_json::from_value(
587 content,
588 )?)),
589 "execute_request" => Ok(JupyterMessageContent::ExecuteRequest(
590 serde_json::from_value(content)?,
591 )),
592
593 "execute_result" => Ok(JupyterMessageContent::ExecuteResult(
594 serde_json::from_value(content)?,
595 )),
596
597 "history_reply" => Ok(JupyterMessageContent::HistoryReply(serde_json::from_value(
598 content,
599 )?)),
600 "history_request" => Ok(JupyterMessageContent::HistoryRequest(
601 serde_json::from_value(content)?,
602 )),
603
604 "input_reply" => Ok(JupyterMessageContent::InputReply(serde_json::from_value(
605 content,
606 )?)),
607 "input_request" => Ok(JupyterMessageContent::InputRequest(serde_json::from_value(
608 content,
609 )?)),
610
611 "inspect_reply" => Ok(JupyterMessageContent::InspectReply(serde_json::from_value(
612 content,
613 )?)),
614 "inspect_request" => Ok(JupyterMessageContent::InspectRequest(
615 serde_json::from_value(content)?,
616 )),
617
618 "interrupt_reply" => Ok(JupyterMessageContent::InterruptReply(
619 serde_json::from_value(content)?,
620 )),
621 "interrupt_request" => Ok(JupyterMessageContent::InterruptRequest(
622 serde_json::from_value(content)?,
623 )),
624
625 "iopub_welcome" => Ok(JupyterMessageContent::IoPubWelcome(serde_json::from_value(
626 content,
627 )?)),
628
629 "is_complete_reply" => Ok(JupyterMessageContent::IsCompleteReply(
630 serde_json::from_value(content)?,
631 )),
632 "is_complete_request" => Ok(JupyterMessageContent::IsCompleteRequest(
633 serde_json::from_value(content)?,
634 )),
635
636 "kernel_info_reply" => Ok(JupyterMessageContent::KernelInfoReply(
637 serde_json::from_value(content)?,
638 )),
639 "kernel_info_request" => Ok(JupyterMessageContent::KernelInfoRequest(
640 serde_json::from_value(content)?,
641 )),
642
643 "shutdown_reply" => Ok(JupyterMessageContent::ShutdownReply(
644 serde_json::from_value(content)?,
645 )),
646 "shutdown_request" => Ok(JupyterMessageContent::ShutdownRequest(
647 serde_json::from_value(content)?,
648 )),
649
650 "status" => Ok(JupyterMessageContent::Status(serde_json::from_value(
651 content,
652 )?)),
653
654 "stream" => Ok(JupyterMessageContent::StreamContent(
655 serde_json::from_value(content)?,
656 )),
657
658 "update_display_data" => Ok(JupyterMessageContent::UpdateDisplayData(
659 serde_json::from_value(content)?,
660 )),
661
662 _ => Ok(JupyterMessageContent::UnknownMessage(UnknownMessage {
663 msg_type: msg_type.to_string(),
664 content,
665 })),
666 }
667 }
668}
669
670macro_rules! impl_message_traits {
671 ($($name:ident),*) => {
672 $(
673 impl $name {
674 #[doc = concat!("Create a new `JupyterMessage`, assigning the parent for a `", stringify!($name), "` message.\n")]
675 #[doc = concat!("use jupyter_protocol::", stringify!($name), ";\n")]
683 #[doc = concat!("let child_message = ", stringify!($name), "{\n")]
690 #[must_use]
697 pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
698 JupyterMessage::new(self.clone(), Some(parent))
699 }
700 }
701
702 impl From<$name> for JupyterMessage {
703 #[doc(hidden)]
704 #[doc = concat!("Create a new `JupyterMessage` for a `", stringify!($name), "`.\n\n")]
705 fn from(content: $name) -> Self {
708 JupyterMessage::new(content, None)
709 }
710 }
711
712 impl From<$name> for JupyterMessageContent {
713 #[doc = concat!("Create a new `JupyterMessageContent` for a `", stringify!($name), "`.\n\n")]
714 fn from(content: $name) -> Self {
715 JupyterMessageContent::$name(content)
716 }
717 }
718 )*
719 };
720}
721
722impl From<JupyterMessageContent> for JupyterMessage {
723 fn from(content: JupyterMessageContent) -> Self {
724 JupyterMessage::new(content, None)
725 }
726}
727
728impl_message_traits!(
729 ClearOutput,
730 CommClose,
731 CommInfoReply,
732 CommInfoRequest,
733 CommMsg,
734 CommOpen,
735 CompleteReply,
736 CompleteRequest,
737 DebugReply,
738 DebugRequest,
739 DisplayData,
740 ErrorOutput,
741 ExecuteInput,
742 ExecuteReply,
743 ExecuteRequest,
744 ExecuteResult,
745 HistoryReply,
746 InputReply,
748 InputRequest,
749 InspectReply,
750 InspectRequest,
751 InterruptReply,
752 InterruptRequest,
753 IoPubWelcome,
754 IsCompleteReply,
755 IsCompleteRequest,
756 KernelInfoRequest,
758 ShutdownReply,
759 ShutdownRequest,
760 Status,
761 StreamContent,
762 UpdateDisplayData,
763 UnknownMessage
764);
765
766impl KernelInfoReply {
768 pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
769 JupyterMessage::new(
770 JupyterMessageContent::KernelInfoReply(Box::new(self.clone())),
771 Some(parent),
772 )
773 }
774}
775
776impl From<KernelInfoReply> for JupyterMessage {
777 fn from(content: KernelInfoReply) -> Self {
778 JupyterMessage::new(
779 JupyterMessageContent::KernelInfoReply(Box::new(content)),
780 None,
781 )
782 }
783}
784
785impl From<KernelInfoReply> for JupyterMessageContent {
786 fn from(content: KernelInfoReply) -> Self {
787 JupyterMessageContent::KernelInfoReply(Box::new(content))
788 }
789}
790
791impl HistoryRequest {
792 #[must_use]
818 pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
819 JupyterMessage::new(self.clone(), Some(parent))
820 }
821}
822
823impl From<HistoryRequest> for JupyterMessage {
824 #[doc(hidden)]
825 fn from(content: HistoryRequest) -> Self {
829 JupyterMessage::new(content, None)
830 }
831}
832
833impl From<HistoryRequest> for JupyterMessageContent {
834 fn from(content: HistoryRequest) -> Self {
836 JupyterMessageContent::HistoryRequest(content)
837 }
838}
839
840#[derive(Serialize, Deserialize, Debug, Clone)]
855pub struct UnknownMessage {
856 #[serde(skip_serializing, skip_deserializing)]
857 pub msg_type: String,
858 #[serde(flatten)]
859 pub content: Value,
860}
861impl Default for UnknownMessage {
862 fn default() -> Self {
863 Self {
864 msg_type: "unknown".to_string(),
865 content: Value::Null,
866 }
867 }
868}
869
870impl UnknownMessage {
871 pub fn reply(&self, content: serde_json::Value) -> JupyterMessageContent {
875 JupyterMessageContent::UnknownMessage(UnknownMessage {
876 msg_type: self.msg_type.replace("_request", "_reply"),
877 content,
878 })
879 }
880}
881
882#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
884#[serde(rename_all = "lowercase")]
885pub enum ReplyStatus {
886 #[default]
887 Ok,
888 Error,
889 Aborted,
890}
891
892#[derive(Serialize, Deserialize, Debug, Clone, Default)]
893pub struct ReplyError {
894 pub ename: String,
895 pub evalue: String,
896 pub traceback: Vec<String>,
897}
898
899#[derive(Serialize, Deserialize, Debug, Clone, Default)]
901pub struct ClearOutput {
902 pub wait: bool,
906}
907
908#[derive(Serialize, Deserialize, Debug, Clone)]
912pub struct ExecuteRequest {
913 pub code: String,
914 pub silent: bool,
915 pub store_history: bool,
916 #[serde(serialize_with = "serialize_user_expressions")]
917 pub user_expressions: Option<HashMap<String, String>>,
918 #[serde(default = "default_allow_stdin")]
919 pub allow_stdin: bool,
920 #[serde(default = "default_stop_on_error")]
921 pub stop_on_error: bool,
922}
923
924fn serialize_user_expressions<S>(
928 user_expressions: &Option<HashMap<String, String>>,
929 serializer: S,
930) -> Result<S::Ok, S::Error>
931where
932 S: serde::Serializer,
933{
934 match user_expressions {
935 Some(user_expressions) => user_expressions.serialize(serializer),
936 None => serde_json::Map::new().serialize(serializer),
937 }
938}
939
940fn default_allow_stdin() -> bool {
941 false
942}
943
944fn default_stop_on_error() -> bool {
945 true
946}
947
948impl ExecuteRequest {
949 pub fn new(code: String) -> Self {
950 Self {
951 code,
952 ..Default::default()
953 }
954 }
955}
956
957impl Default for ExecuteRequest {
958 fn default() -> Self {
959 Self {
960 code: "".to_string(),
961 silent: false,
962 store_history: true,
963 user_expressions: None,
964 allow_stdin: false,
965 stop_on_error: true,
966 }
967 }
968}
969
970#[derive(Serialize, Deserialize, Debug, Clone)]
977#[serde(tag = "status")]
978pub enum ExpressionResult {
979 #[serde(rename = "ok")]
980 Ok {
981 data: Media,
982 #[serde(default)]
983 metadata: serde_json::Map<String, Value>,
984 },
985 #[serde(rename = "error")]
986 Error {
987 ename: String,
988 evalue: String,
989 traceback: Vec<String>,
990 },
991}
992
993#[derive(Serialize, Deserialize, Debug, Clone)]
1001pub struct ExecuteReply {
1002 #[serde(default)]
1003 pub status: ReplyStatus,
1004 #[serde(default)]
1006 pub execution_count: ExecutionCount,
1007
1008 #[serde(default)]
1009 pub payload: Vec<Payload>,
1010 #[serde(default)]
1011 pub user_expressions: Option<HashMap<String, ExpressionResult>>,
1012
1013 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1014 pub error: Option<Box<ReplyError>>,
1015}
1016impl Default for ExecuteReply {
1017 fn default() -> Self {
1018 Self {
1019 status: ReplyStatus::Ok,
1020 execution_count: ExecutionCount::new(0),
1021 payload: Vec::new(),
1022 user_expressions: None,
1023 error: None,
1024 }
1025 }
1026}
1027
1028#[derive(Serialize, Deserialize, Debug, Clone)]
1033#[serde(rename_all = "snake_case")]
1034#[serde(tag = "source")]
1035pub enum Payload {
1036 Page {
1037 data: Media,
1038 start: usize,
1039 },
1040 SetNextInput {
1041 text: String,
1042 replace: bool,
1043 },
1044 EditMagic {
1045 filename: String,
1046 line_number: usize,
1047 },
1048 AskExit {
1049 keepkernel: bool,
1051 },
1052}
1053
1054#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
1058pub struct KernelInfoRequest {}
1059
1060#[derive(Serialize, Deserialize, Debug, Clone)]
1064pub struct KernelInfoReply {
1065 #[serde(default)]
1069 pub status: ReplyStatus,
1070 pub protocol_version: String,
1071 #[serde(default)]
1074 pub implementation: String,
1075 #[serde(default)]
1078 pub implementation_version: String,
1079 pub language_info: LanguageInfo,
1080 #[serde(default)]
1081 pub banner: String,
1082 #[serde(default)]
1083 pub help_links: Vec<HelpLink>,
1084 #[serde(default = "default_debugger")]
1085 pub debugger: bool,
1086 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1087 pub error: Option<Box<ReplyError>>,
1088}
1089
1090fn default_debugger() -> bool {
1091 false
1092}
1093
1094#[derive(Serialize, Deserialize, Debug, Clone)]
1095#[serde(untagged)]
1096pub enum CodeMirrorMode {
1097 Simple(String),
1098 CustomMode { name: String, version: usize },
1099}
1100
1101#[derive(Serialize, Deserialize, Debug, Clone)]
1102pub struct CodeMirrorModeObject {
1103 pub name: String,
1104 pub version: usize,
1105}
1106
1107impl CodeMirrorMode {
1108 pub fn typescript() -> Self {
1109 Self::Simple("typescript".to_string())
1110 }
1111
1112 pub fn python() -> Self {
1113 Self::Simple("python".to_string())
1114 }
1115
1116 pub fn ipython_code_mirror_mode() -> Self {
1117 Self::CustomMode {
1118 name: "ipython".to_string(),
1119 version: 3,
1120 }
1121 }
1122}
1123
1124#[derive(Serialize, Deserialize, Debug, Clone)]
1125pub struct LanguageInfo {
1126 pub name: String,
1127 pub version: String,
1128 #[serde(skip_serializing_if = "Option::is_none")]
1129 pub mimetype: Option<String>,
1130 #[serde(skip_serializing_if = "Option::is_none")]
1131 pub file_extension: Option<String>,
1132 #[serde(skip_serializing_if = "Option::is_none")]
1133 pub pygments_lexer: Option<String>,
1134 #[serde(skip_serializing_if = "Option::is_none")]
1135 pub codemirror_mode: Option<CodeMirrorMode>,
1136 #[serde(skip_serializing_if = "Option::is_none")]
1137 pub nbconvert_exporter: Option<String>,
1138}
1139
1140#[derive(Serialize, Deserialize, Debug, Clone)]
1141pub struct HelpLink {
1142 pub text: String,
1143 pub url: String,
1144}
1145
1146#[derive(Serialize, Deserialize, Debug, Clone)]
1147pub enum Stdio {
1148 #[serde(rename = "stdout")]
1149 Stdout,
1150 #[serde(rename = "stderr")]
1151 Stderr,
1152}
1153
1154#[derive(Serialize, Deserialize, Debug, Clone)]
1196pub struct StreamContent {
1197 pub name: Stdio,
1198 pub text: String,
1199}
1200impl Default for StreamContent {
1201 fn default() -> Self {
1202 Self {
1203 name: Stdio::Stdout,
1204 text: String::new(),
1205 }
1206 }
1207}
1208
1209impl StreamContent {
1210 pub fn stdout(text: &str) -> Self {
1211 Self {
1212 name: Stdio::Stdout,
1213 text: text.to_string(),
1214 }
1215 }
1216
1217 pub fn stderr(text: &str) -> Self {
1218 Self {
1219 name: Stdio::Stderr,
1220 text: text.to_string(),
1221 }
1222 }
1223}
1224
1225#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1227pub struct Transient {
1228 #[serde(skip_serializing_if = "Option::is_none")]
1229 pub display_id: Option<String>,
1230}
1231
1232#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1272pub struct DisplayData {
1273 pub data: Media,
1274 pub metadata: serde_json::Map<String, Value>,
1275 #[serde(default, skip_serializing_if = "Option::is_none")]
1276 pub transient: Option<Transient>,
1277}
1278
1279impl DisplayData {
1280 pub fn new(data: Media) -> Self {
1281 Self {
1282 data,
1283 metadata: Default::default(),
1284 transient: Default::default(),
1285 }
1286 }
1287}
1288
1289impl From<Vec<MediaType>> for DisplayData {
1290 fn from(content: Vec<MediaType>) -> Self {
1291 Self::new(Media::new(content))
1292 }
1293}
1294
1295impl From<MediaType> for DisplayData {
1296 fn from(content: MediaType) -> Self {
1297 Self::new(Media::new(vec![content]))
1298 }
1299}
1300
1301#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1304pub struct UpdateDisplayData {
1305 pub data: Media,
1306 #[serde(default)]
1307 pub metadata: serde_json::Map<String, Value>,
1308 pub transient: Transient,
1309}
1310
1311impl UpdateDisplayData {
1312 pub fn new(data: Media, display_id: &str) -> Self {
1313 Self {
1314 data,
1315 metadata: Default::default(),
1316 transient: Transient {
1317 display_id: Some(display_id.to_string()),
1318 },
1319 }
1320 }
1321}
1322
1323#[derive(Serialize, Deserialize, Debug, Clone)]
1329pub struct ExecuteInput {
1330 pub code: String,
1331 pub execution_count: ExecutionCount,
1332}
1333impl Default for ExecuteInput {
1334 fn default() -> Self {
1335 Self {
1336 code: String::new(),
1337 execution_count: ExecutionCount::new(0),
1338 }
1339 }
1340}
1341
1342#[derive(Serialize, Deserialize, Debug, Clone)]
1366pub struct ExecuteResult {
1367 pub execution_count: ExecutionCount,
1368 pub data: Media,
1369 #[serde(default)]
1370 pub metadata: serde_json::Map<String, Value>,
1371 pub transient: Option<Transient>,
1372}
1373impl Default for ExecuteResult {
1374 fn default() -> Self {
1375 Self {
1376 execution_count: ExecutionCount::new(0),
1377 data: Media::default(),
1378 metadata: serde_json::Map::new(),
1379 transient: None,
1380 }
1381 }
1382}
1383
1384impl ExecuteResult {
1385 pub fn new(execution_count: ExecutionCount, data: Media) -> Self {
1386 Self {
1387 execution_count,
1388 data,
1389 metadata: Default::default(),
1390 transient: None,
1391 }
1392 }
1393}
1394
1395impl From<(ExecutionCount, Vec<MediaType>)> for ExecuteResult {
1396 fn from((execution_count, content): (ExecutionCount, Vec<MediaType>)) -> Self {
1397 Self::new(execution_count, content.into())
1398 }
1399}
1400
1401impl From<(ExecutionCount, MediaType)> for ExecuteResult {
1402 fn from((execution_count, content): (ExecutionCount, MediaType)) -> Self {
1403 Self::new(execution_count, content.into())
1404 }
1405}
1406
1407#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1413pub struct ErrorOutput {
1414 pub ename: String,
1415 pub evalue: String,
1416 pub traceback: Vec<String>,
1417}
1418
1419#[derive(Serialize, Deserialize, Debug, Clone)]
1447pub struct CommOpen {
1448 pub comm_id: CommId,
1449 pub target_name: String,
1450 pub data: serde_json::Map<String, Value>,
1451 #[serde(skip_serializing_if = "Option::is_none")]
1452 pub target_module: Option<String>,
1453}
1454impl Default for CommOpen {
1455 fn default() -> Self {
1456 Self {
1457 comm_id: CommId("".to_string()),
1458 target_name: String::new(),
1459 data: serde_json::Map::new(),
1460 target_module: None,
1461 }
1462 }
1463}
1464
1465#[derive(Serialize, Deserialize, Debug, Clone)]
1484pub struct CommMsg {
1485 pub comm_id: CommId,
1486 pub data: serde_json::Map<String, Value>,
1487}
1488impl Default for CommMsg {
1489 fn default() -> Self {
1490 Self {
1491 comm_id: CommId("".to_string()),
1492 data: serde_json::Map::new(),
1493 }
1494 }
1495}
1496
1497#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1498pub struct CommInfoRequest {
1499 pub target_name: Option<String>,
1500}
1501
1502#[derive(Eq, Hash, PartialEq, Serialize, Deserialize, Debug, Clone)]
1503pub struct CommId(pub String);
1504
1505impl From<CommId> for String {
1506 fn from(comm_id: CommId) -> Self {
1507 comm_id.0
1508 }
1509}
1510
1511impl From<String> for CommId {
1512 fn from(comm_id: String) -> Self {
1513 Self(comm_id)
1514 }
1515}
1516
1517#[derive(Serialize, Deserialize, Debug, Clone)]
1518pub struct CommInfo {
1519 pub target_name: String,
1520}
1521
1522#[derive(Serialize, Deserialize, Debug, Clone)]
1523pub struct CommInfoReply {
1524 #[serde(default)]
1525 pub status: ReplyStatus,
1526 #[serde(default)]
1527 pub comms: HashMap<CommId, CommInfo>,
1528 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1530 pub error: Option<Box<ReplyError>>,
1531}
1532impl Default for CommInfoReply {
1533 fn default() -> Self {
1534 Self {
1535 status: ReplyStatus::Ok,
1536 comms: HashMap::new(),
1537 error: None,
1538 }
1539 }
1540}
1541
1542#[derive(Serialize, Deserialize, Debug, Clone)]
1547pub struct CommClose {
1548 pub comm_id: CommId,
1549 pub data: serde_json::Map<String, Value>,
1550}
1551impl Default for CommClose {
1552 fn default() -> Self {
1553 Self {
1554 comm_id: CommId("".to_string()),
1555 data: serde_json::Map::new(),
1556 }
1557 }
1558}
1559
1560#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1561pub struct ShutdownRequest {
1568 pub restart: bool,
1569}
1570
1571#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1572pub struct InterruptRequest {}
1580
1581#[derive(Serialize, Deserialize, Debug, Clone)]
1582pub struct InterruptReply {
1589 pub status: ReplyStatus,
1590
1591 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1592 pub error: Option<Box<ReplyError>>,
1593}
1594
1595impl Default for InterruptReply {
1596 fn default() -> Self {
1597 Self::new()
1598 }
1599}
1600
1601impl InterruptReply {
1602 pub fn new() -> Self {
1603 Self {
1604 status: ReplyStatus::Ok,
1605 error: None,
1606 }
1607 }
1608}
1609
1610#[derive(Serialize, Deserialize, Debug, Clone)]
1611pub struct ShutdownReply {
1618 pub restart: bool,
1619 pub status: ReplyStatus,
1620
1621 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1622 pub error: Option<Box<ReplyError>>,
1623}
1624impl Default for ShutdownReply {
1625 fn default() -> Self {
1626 Self {
1627 restart: false,
1628 status: ReplyStatus::Ok,
1629 error: None,
1630 }
1631 }
1632}
1633
1634#[derive(Serialize, Deserialize, Debug, Clone)]
1635pub struct InputRequest {
1642 pub prompt: String,
1643 pub password: bool,
1644}
1645impl Default for InputRequest {
1646 fn default() -> Self {
1647 Self {
1648 prompt: "> ".to_string(),
1649 password: false,
1650 }
1651 }
1652}
1653
1654#[derive(Serialize, Deserialize, Debug, Clone)]
1655pub struct InputReply {
1662 #[serde(default)]
1663 pub value: String,
1664 #[serde(default)]
1665 pub status: ReplyStatus,
1666 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1667 pub error: Option<Box<ReplyError>>,
1668}
1669impl Default for InputReply {
1670 fn default() -> Self {
1671 Self {
1672 value: String::new(),
1673 status: ReplyStatus::Ok,
1674 error: None,
1675 }
1676 }
1677}
1678
1679#[derive(Serialize, Deserialize, Debug, Clone)]
1685pub struct InspectRequest {
1686 pub code: String,
1689 pub cursor_pos: usize,
1691 pub detail_level: Option<usize>,
1696}
1697impl Default for InspectRequest {
1698 fn default() -> Self {
1699 Self {
1700 code: String::new(),
1701 cursor_pos: 0,
1702 detail_level: Some(0),
1703 }
1704 }
1705}
1706
1707fn deserialize_null_as_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
1709where
1710 D: serde::Deserializer<'de>,
1711 T: Default + serde::Deserialize<'de>,
1712{
1713 let opt = Option::deserialize(deserializer)?;
1714 Ok(opt.unwrap_or_default())
1715}
1716
1717#[derive(Serialize, Deserialize, Debug, Clone)]
1718pub struct InspectReply {
1719 #[serde(default)]
1720 pub found: bool,
1721 #[serde(default, deserialize_with = "deserialize_null_as_default")]
1723 pub data: Media,
1724 #[serde(default, deserialize_with = "deserialize_null_as_default")]
1725 pub metadata: serde_json::Map<String, Value>,
1726 #[serde(default)]
1727 pub status: ReplyStatus,
1728 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1729 pub error: Option<Box<ReplyError>>,
1730}
1731impl Default for InspectReply {
1732 fn default() -> Self {
1733 Self {
1734 found: false,
1735 data: Media::default(),
1736 metadata: serde_json::Map::new(),
1737 status: ReplyStatus::Ok,
1738 error: None,
1739 }
1740 }
1741}
1742
1743#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1747pub struct CompleteRequest {
1748 pub code: String,
1749 pub cursor_pos: usize,
1750}
1751
1752#[derive(Serialize, Deserialize, Debug, Clone)]
1756pub struct CompleteReply {
1757 #[serde(default)]
1758 pub matches: Vec<String>,
1759 #[serde(default)]
1760 pub cursor_start: usize,
1761 #[serde(default)]
1762 pub cursor_end: usize,
1763 #[serde(default)]
1764 pub metadata: serde_json::Map<String, Value>,
1765 #[serde(default)]
1766 pub status: ReplyStatus,
1767 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1768 pub error: Option<Box<ReplyError>>,
1769}
1770impl Default for CompleteReply {
1771 fn default() -> Self {
1772 Self {
1773 matches: Vec::new(),
1774 cursor_start: 0,
1775 cursor_end: 0,
1776 metadata: serde_json::Map::new(),
1777 status: ReplyStatus::Ok,
1778 error: None,
1779 }
1780 }
1781}
1782
1783#[derive(Serialize, Deserialize, Debug, Clone)]
1784pub struct DebugRequest {
1785 #[serde(flatten)]
1786 pub content: Value,
1787}
1788impl Default for DebugRequest {
1789 fn default() -> Self {
1790 Self {
1791 content: Value::Null,
1792 }
1793 }
1794}
1795
1796#[derive(Serialize, Deserialize, Debug, Clone)]
1797pub struct DebugReply {
1798 #[serde(flatten)]
1799 pub content: Value,
1800}
1801impl Default for DebugReply {
1802 fn default() -> Self {
1803 Self {
1804 content: Value::Null,
1805 }
1806 }
1807}
1808
1809#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1810#[serde(rename_all = "snake_case")]
1811pub enum IsCompleteReplyStatus {
1812 Incomplete,
1815 Complete,
1817 Invalid,
1819 Unknown,
1824}
1825
1826#[derive(Serialize, Deserialize, Debug, Clone)]
1827pub struct IsCompleteReply {
1828 pub status: IsCompleteReplyStatus,
1831 #[serde(default)]
1836 pub indent: String,
1837}
1838impl Default for IsCompleteReply {
1839 fn default() -> Self {
1840 Self {
1841 status: IsCompleteReplyStatus::Unknown,
1842 indent: String::new(),
1843 }
1844 }
1845}
1846
1847impl IsCompleteReply {
1848 pub fn new(status: IsCompleteReplyStatus, indent: String) -> Self {
1849 Self { status, indent }
1850 }
1851
1852 pub fn incomplete(indent: String) -> Self {
1853 Self::new(IsCompleteReplyStatus::Incomplete, indent)
1854 }
1855
1856 pub fn complete() -> Self {
1857 Self::new(IsCompleteReplyStatus::Complete, String::new())
1858 }
1859
1860 pub fn invalid() -> Self {
1861 Self::new(IsCompleteReplyStatus::Invalid, String::new())
1862 }
1863
1864 pub fn unknown() -> Self {
1865 Self::new(IsCompleteReplyStatus::Unknown, String::new())
1866 }
1867}
1868
1869#[derive(Serialize, Deserialize, Debug, Clone)]
1870#[serde(tag = "hist_access_type")]
1871pub enum HistoryRequest {
1872 #[serde(rename = "range")]
1873 Range {
1874 session: Option<i32>,
1875 start: i32,
1876 stop: i32,
1877 output: bool,
1878 raw: bool,
1879 },
1880 #[serde(rename = "tail")]
1881 Tail { n: i32, output: bool, raw: bool },
1882 #[serde(rename = "search")]
1883 Search {
1884 pattern: String,
1885 unique: bool,
1886 output: bool,
1887 raw: bool,
1888 n: i32,
1889 },
1890}
1891impl Default for HistoryRequest {
1892 fn default() -> Self {
1893 Self::Range {
1894 session: None,
1895 start: 0,
1896 stop: 0,
1897 output: false,
1898 raw: false,
1899 }
1900 }
1901}
1902
1903#[derive(Serialize, Deserialize, Debug, Clone)]
1904#[serde(untagged)]
1905pub enum HistoryEntry {
1906 Input(usize, usize, String),
1909 InputOutput(usize, usize, (String, String)),
1912}
1913
1914#[derive(Serialize, Deserialize, Debug, Clone)]
1918pub struct HistoryReply {
1919 pub history: Vec<HistoryEntry>,
1920
1921 pub status: ReplyStatus,
1922 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1923 pub error: Option<Box<ReplyError>>,
1924}
1925impl Default for HistoryReply {
1926 fn default() -> Self {
1927 Self {
1928 history: Vec::new(),
1929 status: ReplyStatus::Ok,
1930 error: None,
1931 }
1932 }
1933}
1934
1935impl HistoryReply {
1936 pub fn new(history: Vec<HistoryEntry>) -> Self {
1937 Self {
1938 history,
1939 status: ReplyStatus::Ok,
1940 error: None,
1941 }
1942 }
1943}
1944
1945#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1949pub struct IsCompleteRequest {
1950 pub code: String,
1951}
1952
1953#[derive(Debug, Clone, PartialEq)]
1954pub enum ExecutionState {
1955 Unknown,
1956 Starting,
1957 Busy,
1958 Idle,
1959 Restarting,
1960 Terminating,
1961 AutoRestarting,
1962 Dead,
1963 Other(String),
1964}
1965
1966impl ExecutionState {
1967 pub fn as_str(&self) -> &str {
1968 match self {
1969 ExecutionState::Unknown => "unknown",
1970 ExecutionState::Terminating => "terminating",
1971 ExecutionState::AutoRestarting => "autorestarting",
1972 ExecutionState::Dead => "dead",
1973 ExecutionState::Busy => "busy",
1974 ExecutionState::Idle => "idle",
1975 ExecutionState::Starting => "starting",
1976 ExecutionState::Restarting => "restarting",
1977 ExecutionState::Other(s) => s,
1978 }
1979 }
1980}
1981
1982impl serde::Serialize for ExecutionState {
1983 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1984 where
1985 S: serde::Serializer,
1986 {
1987 match self {
1988 ExecutionState::Unknown => serializer.serialize_str("unknown"),
1989 ExecutionState::Terminating => serializer.serialize_str("terminating"),
1990 ExecutionState::AutoRestarting => serializer.serialize_str("autorestarting"),
1991 ExecutionState::Dead => serializer.serialize_str("dead"),
1992 ExecutionState::Busy => serializer.serialize_str("busy"),
1993 ExecutionState::Idle => serializer.serialize_str("idle"),
1994 ExecutionState::Starting => serializer.serialize_str("starting"),
1995 ExecutionState::Restarting => serializer.serialize_str("restarting"),
1996 ExecutionState::Other(s) => serializer.serialize_str(s),
1997 }
1998 }
1999}
2000
2001impl<'de> serde::Deserialize<'de> for ExecutionState {
2002 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2003 where
2004 D: serde::Deserializer<'de>,
2005 {
2006 struct ExecutionStateVisitor;
2007
2008 impl serde::de::Visitor<'_> for ExecutionStateVisitor {
2009 type Value = ExecutionState;
2010
2011 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
2012 formatter.write_str("a string representing an execution state")
2013 }
2014 fn visit_str<E>(self, value: &str) -> Result<ExecutionState, E>
2015 where
2016 E: serde::de::Error,
2017 {
2018 match value {
2019 "unknown" => Ok(ExecutionState::Unknown),
2020 "terminating" => Ok(ExecutionState::Terminating),
2021 "autorestarting" => Ok(ExecutionState::AutoRestarting),
2022 "dead" => Ok(ExecutionState::Dead),
2023 "busy" => Ok(ExecutionState::Busy),
2024 "idle" => Ok(ExecutionState::Idle),
2025 "starting" => Ok(ExecutionState::Starting),
2026 "restarting" => Ok(ExecutionState::Restarting),
2027 other => Ok(ExecutionState::Other(other.to_string())),
2028 }
2029 }
2030 }
2031 deserializer.deserialize_str(ExecutionStateVisitor)
2032 }
2033}
2034
2035#[derive(Serialize, Deserialize, Debug, Clone)]
2039pub struct Status {
2040 pub execution_state: ExecutionState,
2041}
2042impl Default for Status {
2043 fn default() -> Self {
2044 Self {
2045 execution_state: ExecutionState::Idle,
2046 }
2047 }
2048}
2049
2050impl Status {
2051 pub fn busy() -> Self {
2052 Self {
2053 execution_state: ExecutionState::Busy,
2054 }
2055 }
2056
2057 pub fn idle() -> Self {
2058 Self {
2059 execution_state: ExecutionState::Idle,
2060 }
2061 }
2062
2063 pub fn starting() -> Self {
2064 Self {
2065 execution_state: ExecutionState::Starting,
2066 }
2067 }
2068
2069 pub fn restarting() -> Self {
2070 Self {
2071 execution_state: ExecutionState::Restarting,
2072 }
2073 }
2074
2075 pub fn other(state: impl Into<String>) -> Self {
2076 Self {
2077 execution_state: ExecutionState::Other(state.into()),
2078 }
2079 }
2080}
2081
2082#[derive(Serialize, Deserialize, Debug, Clone, Default)]
2089pub struct IoPubWelcome {
2090 pub subscription: String,
2093}
2094
2095impl IoPubWelcome {
2096 pub fn new(subscription: String) -> Self {
2097 Self { subscription }
2098 }
2099}
2100
2101#[cfg(test)]
2102mod test {
2103 use serde_json::json;
2104
2105 use super::*;
2106
2107 #[test]
2108 fn test_execute_request_serialize() {
2109 let request = ExecuteRequest {
2110 code: "print('Hello, World!')".to_string(),
2111 silent: false,
2112 store_history: true,
2113 user_expressions: Some(HashMap::new()),
2114 allow_stdin: false,
2115 stop_on_error: true,
2116 };
2117 let request_value = serde_json::to_value(request).unwrap();
2118
2119 let expected_request_value = serde_json::json!({
2120 "code": "print('Hello, World!')",
2121 "silent": false,
2122 "store_history": true,
2123 "user_expressions": {},
2124 "allow_stdin": false,
2125 "stop_on_error": true
2126 });
2127
2128 assert_eq!(request_value, expected_request_value);
2129 }
2130
2131 #[test]
2132 fn test_execute_request_user_expressions_serializes_to_empty_dict() {
2133 let request = ExecuteRequest {
2134 code: "print('Hello, World!')".to_string(),
2135 silent: false,
2136 store_history: true,
2137 user_expressions: None,
2138 allow_stdin: false,
2139 stop_on_error: true,
2140 };
2141 let request_value = serde_json::to_value(request).unwrap();
2142
2143 let expected_request_value = serde_json::json!({
2144 "code": "print('Hello, World!')",
2145 "silent": false,
2146 "store_history": true,
2147 "user_expressions": {},
2148 "allow_stdin": false,
2149 "stop_on_error": true
2150 });
2151
2152 assert_eq!(request_value, expected_request_value);
2153 }
2154
2155 #[test]
2156 fn test_into_various() {
2157 let kernel_info_request = KernelInfoRequest {};
2158 let content: JupyterMessageContent = kernel_info_request.clone().into();
2159 let message: JupyterMessage = content.into();
2160 assert!(message.parent_header.is_none());
2161 match message.content {
2162 JupyterMessageContent::KernelInfoRequest(req) => {
2163 assert_eq!(req, kernel_info_request);
2164 }
2165 _ => panic!("Expected KernelInfoRequest"),
2166 }
2167
2168 let kernel_info_request = KernelInfoRequest {};
2169 let message: JupyterMessage = kernel_info_request.clone().into();
2170 assert!(message.parent_header.is_none());
2171 match message.content {
2172 JupyterMessageContent::KernelInfoRequest(req) => {
2173 assert_eq!(req, kernel_info_request);
2174 }
2175 _ => panic!("Expected KernelInfoRequest"),
2176 }
2177 }
2178
2179 #[test]
2180 fn test_default() {
2181 let msg: JupyterMessage = ExecuteRequest {
2182 code: "import this".to_string(),
2183 ..Default::default()
2184 }
2185 .into();
2186
2187 assert_eq!(msg.header.msg_type, "execute_request");
2188 assert_eq!(msg.header.msg_id.len(), 36);
2189
2190 match msg.content {
2191 JupyterMessageContent::ExecuteRequest(req) => {
2192 assert_eq!(req.code, "import this");
2193 assert!(!req.silent);
2194 assert!(req.store_history);
2195 assert_eq!(req.user_expressions, None);
2196 assert!(!req.allow_stdin);
2197 assert!(req.stop_on_error);
2198 }
2199 _ => panic!("Expected ExecuteRequest"),
2200 }
2201 }
2202
2203 #[test]
2204 fn test_deserialize_payload() {
2205 let raw_execute_reply_content = r#"
2206 {
2207 "status": "ok",
2208 "execution_count": 1,
2209 "payload": [{
2210 "source": "page",
2211 "data": {
2212 "text/html": "<h1>Hello</h1>",
2213 "text/plain": "Hello"
2214 },
2215 "start": 0
2216 }],
2217 "user_expressions": {}
2218 }
2219 "#;
2220
2221 let execute_reply: ExecuteReply = serde_json::from_str(raw_execute_reply_content).unwrap();
2222
2223 assert_eq!(execute_reply.status, ReplyStatus::Ok);
2224 assert_eq!(execute_reply.execution_count, ExecutionCount::new(1));
2225
2226 let payload = execute_reply.payload.clone();
2227
2228 assert_eq!(payload.len(), 1);
2229 let payload = payload.first().unwrap();
2230
2231 let media = match payload {
2232 Payload::Page { data, .. } => data,
2233 _ => panic!("Expected Page payload type"),
2234 };
2235
2236 let media = serde_json::to_value(media).unwrap();
2237
2238 let expected_media = serde_json::json!({
2239 "text/html": "<h1>Hello</h1>",
2240 "text/plain": "Hello"
2241 });
2242
2243 assert_eq!(media, expected_media);
2244 }
2245
2246 #[test]
2247 pub fn test_display_data_various_data() {
2248 let display_data = DisplayData {
2249 data: serde_json::from_value(json!({
2250 "text/plain": "Hello, World!",
2251 "text/html": "<h1>Hello, World!</h1>",
2252 "application/json": {
2253 "hello": "world",
2254 "foo": "bar",
2255 "ok": [1, 2, 3],
2256 }
2257 }))
2258 .unwrap(),
2259 ..Default::default()
2260 };
2261
2262 let display_data_value = serde_json::to_value(display_data).unwrap();
2263
2264 let expected_display_data_value = serde_json::json!({
2265 "data": {
2266 "text/plain": "Hello, World!",
2267 "text/html": "<h1>Hello, World!</h1>",
2268 "application/json": {
2269 "hello": "world",
2270 "foo": "bar",
2271 "ok": [1, 2, 3]
2272 }
2273 },
2274 "metadata": {}
2275 });
2276
2277 assert_eq!(display_data_value, expected_display_data_value);
2278 }
2279
2280 use std::mem::size_of;
2281
2282 macro_rules! size_of_variant {
2283 ($variant:ty) => {
2284 let size = size_of::<$variant>();
2285 println!("The size of {} is: {} bytes", stringify!($variant), size);
2286
2287 assert!(size <= 96);
2288 };
2289 }
2290
2291 #[test]
2292 fn test_enum_variant_sizes() {
2293 size_of_variant!(ClearOutput);
2294 size_of_variant!(CommClose);
2295 size_of_variant!(CommInfoReply);
2296 size_of_variant!(CommInfoRequest);
2297 size_of_variant!(CommMsg);
2298 size_of_variant!(CommOpen);
2299 size_of_variant!(CompleteReply);
2300 size_of_variant!(CompleteRequest);
2301 size_of_variant!(DebugReply);
2302 size_of_variant!(DebugRequest);
2303 size_of_variant!(DisplayData);
2304 size_of_variant!(ErrorOutput);
2305 size_of_variant!(ExecuteInput);
2306 size_of_variant!(ExecuteReply);
2307 size_of_variant!(ExecuteRequest);
2308 size_of_variant!(ExecuteResult);
2309 size_of_variant!(HistoryReply);
2310 size_of_variant!(HistoryRequest);
2311 size_of_variant!(InputReply);
2312 size_of_variant!(InputRequest);
2313 size_of_variant!(InspectReply);
2314 size_of_variant!(InspectRequest);
2315 size_of_variant!(InterruptReply);
2316 size_of_variant!(InterruptRequest);
2317 size_of_variant!(IsCompleteReply);
2318 size_of_variant!(IsCompleteRequest);
2319 size_of_variant!(Box<KernelInfoReply>);
2320 size_of_variant!(KernelInfoRequest);
2321 size_of_variant!(ShutdownReply);
2322 size_of_variant!(ShutdownRequest);
2323 size_of_variant!(Status);
2324 size_of_variant!(StreamContent);
2325 size_of_variant!(UnknownMessage);
2326 size_of_variant!(UpdateDisplayData);
2327 }
2328
2329 #[test]
2330 fn test_jupyter_message_content_enum_size() {
2331 let size = size_of::<JupyterMessageContent>();
2332 println!("The size of JupyterMessageContent is: {}", size);
2333 assert!(size > 0);
2334 assert!(size <= 104);
2335 }
2336
2337 #[test]
2338 fn test_jupyter_message_parent_header_serializes_to_empty_dict() {
2339 let request = ExecuteRequest {
2340 code: "1 + 1".to_string(),
2341 ..Default::default()
2342 };
2343 let message = JupyterMessage::from(request);
2344
2345 let serialized_message = serde_json::to_value(message).unwrap();
2346
2347 let parent_header = serialized_message.get("parent_header").unwrap();
2349 assert!(parent_header.is_object());
2350 assert!(parent_header.as_object().unwrap().is_empty());
2351 }
2352
2353 #[test]
2354 fn test_user_expressions_serialization() {
2355 let request = ExecuteRequest {
2356 code: "pass".to_string(),
2357 silent: false,
2358 store_history: true,
2359 user_expressions: Some(HashMap::from([(
2360 String::from("expression"),
2361 String::from("42 + 7"),
2362 )])),
2363 allow_stdin: false,
2364 stop_on_error: true,
2365 };
2366 let request_value = serde_json::to_value(request.clone()).unwrap();
2367
2368 let expected_request_value = serde_json::json!({
2369 "code": "pass",
2370 "silent": false,
2371 "store_history": true,
2372 "user_expressions": {"expression": "42 + 7"},
2373 "allow_stdin": false,
2374 "stop_on_error": true
2375 });
2376
2377 assert_eq!(request_value, expected_request_value);
2378
2379 let deserialized_request: ExecuteRequest = serde_json::from_value(request_value).unwrap();
2380 assert_eq!(
2381 deserialized_request.user_expressions,
2382 request.user_expressions
2383 );
2384 }
2385
2386 #[test]
2387 fn test_execute_reply_user_expressions_deserialization() {
2388 let reply_json = serde_json::json!({
2389 "status": "ok",
2390 "execution_count": 1,
2391 "payload": [],
2392 "user_expressions": {
2393 "answer": {
2394 "status": "ok",
2395 "data": {"text/plain": "55"},
2396 "metadata": {}
2397 },
2398 "bad_expr": {
2399 "status": "error",
2400 "ename": "NameError",
2401 "evalue": "name 'undefined_var' is not defined",
2402 "traceback": ["Traceback ...", "NameError: name 'undefined_var' is not defined"]
2403 }
2404 }
2405 });
2406
2407 let reply: ExecuteReply = serde_json::from_value(reply_json).unwrap();
2408 assert_eq!(reply.execution_count.value(), 1);
2409
2410 let user_exprs = reply.user_expressions.unwrap();
2411 assert_eq!(user_exprs.len(), 2);
2412
2413 match &user_exprs["answer"] {
2415 ExpressionResult::Ok { data, metadata: _ } => {
2416 let plain = data.content.iter().find_map(|m| match m {
2417 MediaType::Plain(text) => Some(text.as_str()),
2418 _ => None,
2419 });
2420 assert_eq!(plain, Some("55"));
2421 }
2422 other => panic!("Expected Ok variant, got {:?}", other),
2423 }
2424
2425 match &user_exprs["bad_expr"] {
2427 ExpressionResult::Error {
2428 ename,
2429 evalue,
2430 traceback,
2431 } => {
2432 assert_eq!(ename, "NameError");
2433 assert_eq!(evalue, "name 'undefined_var' is not defined");
2434 assert_eq!(traceback.len(), 2);
2435 }
2436 other => panic!("Expected Error variant, got {:?}", other),
2437 }
2438 }
2439
2440 #[test]
2441 fn test_execute_reply_without_user_expressions() {
2442 let reply_json = serde_json::json!({
2443 "status": "ok",
2444 "execution_count": 1,
2445 "payload": []
2446 });
2447
2448 let reply: ExecuteReply = serde_json::from_value(reply_json).unwrap();
2449 assert!(reply.user_expressions.is_none());
2450 }
2451
2452 #[test]
2453 fn test_execute_reply_without_execution_count() {
2454 let reply_json = serde_json::json!({
2455 "status": "aborted",
2456 "payload": []
2457 });
2458 let reply: ExecuteReply = serde_json::from_value(reply_json).unwrap();
2459 assert_eq!(reply.execution_count, ExecutionCount::new(0));
2460 assert_eq!(reply.status, ReplyStatus::Aborted);
2461 }
2462
2463 #[test]
2464 fn test_jupyter_message_parent_header_deserialize() {
2465 let msg = r#"
2466 {
2467 "buffers": [],
2468 "channel": "shell",
2469 "content": {},
2470 "header": {
2471 "date": "2025-05-14T14:32:23.490Z",
2472 "msg_id": "44bd6b44-78a1-4892-87df-c0861a005d56",
2473 "msg_type": "kernel_info_request",
2474 "session": "b75bddaa-6d69-4340-ba13-81516192370e",
2475 "username": "",
2476 "version": "5.2"
2477 },
2478 "metadata": {},
2479 "parent_header": {
2480 "date": "2025-05-14T14:32:23.490Z",
2481 "msg_id": "2aaf8916-6b83-4f5a-80dd-633e94f5d8e1",
2482 "msg_type": "kernel_info_request",
2483 "session": "e2a3165d-76a8-4fef-850f-712102589660",
2484 "username": "",
2485 "version": "5.2"
2486 }
2487}
2488 "#;
2489
2490 let message: JupyterMessage = serde_json::from_str(msg).unwrap();
2491 assert!(message.parent_header.is_some());
2492 assert_eq!(
2493 message.parent_header.as_ref().unwrap().msg_type,
2494 "kernel_info_request"
2495 );
2496 assert_eq!(
2497 message.parent_header.as_ref().unwrap().msg_id,
2498 "2aaf8916-6b83-4f5a-80dd-633e94f5d8e1"
2499 );
2500 assert_eq!(
2501 message.header.msg_id,
2502 "44bd6b44-78a1-4892-87df-c0861a005d56"
2503 );
2504 }
2505
2506 #[test]
2507 fn test_jupyter_message_empty_parent_header_deserialize() {
2508 let msg = r#"
2509 {
2510 "buffers": [],
2511 "channel": "shell",
2512 "content": {},
2513 "header": {
2514 "date": "2025-05-14T14:32:23.490Z",
2515 "msg_id": "44bd6b44-78a1-4892-87df-c0861a005d56",
2516 "msg_type": "kernel_info_request",
2517 "session": "b75bddaa-6d69-4340-ba13-81516192370e",
2518 "username": "",
2519 "version": "5.2"
2520 },
2521 "metadata": {},
2522 "parent_header": {}
2523}
2524 "#;
2525
2526 let message: JupyterMessage = serde_json::from_str(msg).unwrap();
2527 assert!(message.parent_header.is_none());
2528 assert_eq!(message.header.msg_type, "kernel_info_request");
2529 assert_eq!(
2530 message.header.msg_id,
2531 "44bd6b44-78a1-4892-87df-c0861a005d56"
2532 );
2533 }
2534
2535 #[test]
2536 fn test_execution_state_other_serde() {
2537 let json = r#""busy""#;
2538 let state: ExecutionState = serde_json::from_str(json).unwrap();
2539 assert_eq!(state, ExecutionState::Busy);
2540 let serialized = serde_json::to_string(&state).unwrap();
2541 assert_eq!(serialized, "\"busy\"");
2542
2543 let state = ExecutionState::Idle;
2544 let serialized = serde_json::to_string(&state).unwrap();
2545 assert_eq!(serialized, "\"idle\"");
2546 let state: ExecutionState = serde_json::from_str(&serialized).unwrap();
2547 assert_eq!(state, ExecutionState::Idle);
2548
2549 let json = r#""disconnected""#;
2550 let state: ExecutionState = serde_json::from_str(json).unwrap();
2551 assert_eq!(state, ExecutionState::Other("disconnected".to_string()));
2552 let serialized = serde_json::to_string(&state).unwrap();
2553 assert_eq!(serialized, "\"disconnected\"");
2554 }
2555
2556 #[test]
2557 fn test_iopub_welcome_message() {
2558 let welcome = IoPubWelcome::new("".to_string());
2560 assert_eq!(welcome.subscription, "");
2561
2562 let welcome_value = serde_json::to_value(&welcome).unwrap();
2564 let expected_value = serde_json::json!({
2565 "subscription": ""
2566 });
2567 assert_eq!(welcome_value, expected_value);
2568
2569 let json_str = r#"{"subscription": ""}"#;
2571 let deserialized: IoPubWelcome = serde_json::from_str(json_str).unwrap();
2572 assert_eq!(deserialized.subscription, "");
2573
2574 let welcome_with_topic = IoPubWelcome::new("kernel.output".to_string());
2576 assert_eq!(welcome_with_topic.subscription, "kernel.output");
2577
2578 let message: JupyterMessage = welcome.clone().into();
2580 assert_eq!(message.header.msg_type, "iopub_welcome");
2581 match message.content {
2582 JupyterMessageContent::IoPubWelcome(w) => {
2583 assert_eq!(w.subscription, "");
2584 }
2585 _ => panic!("Expected IoPubWelcome"),
2586 }
2587
2588 let content_value = serde_json::json!({"subscription": "test_topic"});
2590 let content =
2591 JupyterMessageContent::from_type_and_content("iopub_welcome", content_value).unwrap();
2592 match content {
2593 JupyterMessageContent::IoPubWelcome(w) => {
2594 assert_eq!(w.subscription, "test_topic");
2595 }
2596 _ => panic!("Expected IoPubWelcome"),
2597 }
2598 }
2599
2600 #[test]
2601 fn test_deserialize_jupyter_message() {
2602 let original_message = JupyterMessage::new(
2603 ExecuteRequest::new("print('Hello world!')".to_string()),
2604 None,
2605 );
2606 let serialized = serde_json::to_string(&original_message).unwrap();
2607 let deserialized: JupyterMessage = serde_json::from_str(&serialized).unwrap();
2608 assert_eq!(original_message.header.msg_id, deserialized.header.msg_id);
2609 assert_eq!(
2610 original_message.header.msg_type,
2611 deserialized.header.msg_type
2612 );
2613 match deserialized.content {
2614 JupyterMessageContent::ExecuteRequest(req) => {
2615 assert_eq!(req.code, "print('Hello world!')");
2616 }
2617 _ => panic!("Expected ExecuteRequest"),
2618 }
2619 }
2620
2621 #[test]
2622 fn test_header_missing_date_defaults_to_epoch() {
2623 let header_json = json!({
2625 "msg_id": "test-msg-id",
2626 "username": "testuser",
2627 "session": "test-session",
2628 "msg_type": "execute_request",
2629 "version": "5.3"
2630 });
2631
2632 let header: Header = serde_json::from_value(header_json).unwrap();
2633 assert_eq!(header.msg_id, "test-msg-id");
2634 assert_eq!(header.date, DateTime::<Utc>::from_timestamp(0, 0).unwrap());
2636 }
2637
2638 #[test]
2639 fn test_header_with_date_parses_correctly() {
2640 let header_json = json!({
2641 "msg_id": "test-msg-id",
2642 "username": "testuser",
2643 "session": "test-session",
2644 "date": "2025-05-14T14:32:23.490Z",
2645 "msg_type": "execute_request",
2646 "version": "5.3"
2647 });
2648
2649 let header: Header = serde_json::from_value(header_json).unwrap();
2650 assert_ne!(header.date, DateTime::<Utc>::from_timestamp(0, 0).unwrap());
2651 }
2652
2653 #[test]
2654 fn test_kernel_info_reply_missing_status_defaults_to_ok() {
2655 let reply_json = json!({
2657 "protocol_version": "5.3",
2658 "implementation": "test_kernel",
2659 "implementation_version": "1.0.0",
2660 "language_info": {
2661 "name": "python",
2662 "version": "3.9.0"
2663 },
2664 "banner": "Test Kernel",
2665 "help_links": [],
2666 "debugger": false
2667 });
2668
2669 let reply: KernelInfoReply = serde_json::from_value(reply_json).unwrap();
2670 assert_eq!(reply.status, ReplyStatus::Ok);
2672 }
2673
2674 #[test]
2675 fn test_kernel_info_reply_with_status_parses_correctly() {
2676 let reply_json = json!({
2677 "status": "error",
2678 "protocol_version": "5.3",
2679 "implementation": "test_kernel",
2680 "implementation_version": "1.0.0",
2681 "language_info": {
2682 "name": "python",
2683 "version": "3.9.0"
2684 },
2685 "banner": "Test Kernel",
2686 "help_links": [],
2687 "debugger": false
2688 });
2689
2690 let reply: KernelInfoReply = serde_json::from_value(reply_json).unwrap();
2691 assert_eq!(reply.status, ReplyStatus::Error);
2692 }
2693}