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 IsCompleteReply(IsCompleteReply),
420 IsCompleteRequest(IsCompleteRequest),
421 KernelInfoReply(Box<KernelInfoReply>),
424 KernelInfoRequest(KernelInfoRequest),
425 ShutdownReply(ShutdownReply),
426 ShutdownRequest(ShutdownRequest),
427 Status(Status),
428 StreamContent(StreamContent),
429 UnknownMessage(UnknownMessage),
430 UpdateDisplayData(UpdateDisplayData),
431}
432
433impl JupyterMessageContent {
434 pub fn message_type(&self) -> &str {
435 match self {
436 JupyterMessageContent::ClearOutput(_) => "clear_output",
437 JupyterMessageContent::CommClose(_) => "comm_close",
438 JupyterMessageContent::CommInfoReply(_) => "comm_info_reply",
439 JupyterMessageContent::CommInfoRequest(_) => "comm_info_request",
440 JupyterMessageContent::CommMsg(_) => "comm_msg",
441 JupyterMessageContent::CommOpen(_) => "comm_open",
442 JupyterMessageContent::CompleteReply(_) => "complete_reply",
443 JupyterMessageContent::CompleteRequest(_) => "complete_request",
444 JupyterMessageContent::DebugReply(_) => "debug_reply",
445 JupyterMessageContent::DebugRequest(_) => "debug_request",
446 JupyterMessageContent::DisplayData(_) => "display_data",
447 JupyterMessageContent::ErrorOutput(_) => "error",
448 JupyterMessageContent::ExecuteInput(_) => "execute_input",
449 JupyterMessageContent::ExecuteReply(_) => "execute_reply",
450 JupyterMessageContent::ExecuteRequest(_) => "execute_request",
451 JupyterMessageContent::ExecuteResult(_) => "execute_result",
452 JupyterMessageContent::HistoryReply(_) => "history_reply",
453 JupyterMessageContent::HistoryRequest(_) => "history_request",
454 JupyterMessageContent::InputReply(_) => "input_reply",
455 JupyterMessageContent::InputRequest(_) => "input_request",
456 JupyterMessageContent::InspectReply(_) => "inspect_reply",
457 JupyterMessageContent::InspectRequest(_) => "inspect_request",
458 JupyterMessageContent::InterruptReply(_) => "interrupt_reply",
459 JupyterMessageContent::InterruptRequest(_) => "interrupt_request",
460 JupyterMessageContent::IsCompleteReply(_) => "is_complete_reply",
461 JupyterMessageContent::IsCompleteRequest(_) => "is_complete_request",
462 JupyterMessageContent::KernelInfoReply(_) => "kernel_info_reply",
463 JupyterMessageContent::KernelInfoRequest(_) => "kernel_info_request",
464 JupyterMessageContent::ShutdownReply(_) => "shutdown_reply",
465 JupyterMessageContent::ShutdownRequest(_) => "shutdown_request",
466 JupyterMessageContent::Status(_) => "status",
467 JupyterMessageContent::StreamContent(_) => "stream",
468 JupyterMessageContent::UnknownMessage(unk) => unk.msg_type.as_str(),
469 JupyterMessageContent::UpdateDisplayData(_) => "update_display_data",
470 }
471 }
472
473 pub fn from_type_and_content(msg_type: &str, content: Value) -> serde_json::Result<Self> {
474 match msg_type {
475 "clear_output" => Ok(JupyterMessageContent::ClearOutput(serde_json::from_value(
476 content,
477 )?)),
478
479 "comm_close" => Ok(JupyterMessageContent::CommClose(serde_json::from_value(
480 content,
481 )?)),
482
483 "comm_info_reply" => Ok(JupyterMessageContent::CommInfoReply(
484 serde_json::from_value(content)?,
485 )),
486 "comm_info_request" => Ok(JupyterMessageContent::CommInfoRequest(
487 serde_json::from_value(content)?,
488 )),
489
490 "comm_msg" => Ok(JupyterMessageContent::CommMsg(serde_json::from_value(
491 content,
492 )?)),
493 "comm_open" => Ok(JupyterMessageContent::CommOpen(serde_json::from_value(
494 content,
495 )?)),
496
497 "complete_reply" => Ok(JupyterMessageContent::CompleteReply(
498 serde_json::from_value(content)?,
499 )),
500 "complete_request" => Ok(JupyterMessageContent::CompleteRequest(
501 serde_json::from_value(content)?,
502 )),
503
504 "debug_reply" => Ok(JupyterMessageContent::DebugReply(serde_json::from_value(
505 content,
506 )?)),
507 "debug_request" => Ok(JupyterMessageContent::DebugRequest(serde_json::from_value(
508 content,
509 )?)),
510
511 "display_data" => Ok(JupyterMessageContent::DisplayData(serde_json::from_value(
512 content,
513 )?)),
514
515 "error" => Ok(JupyterMessageContent::ErrorOutput(serde_json::from_value(
516 content,
517 )?)),
518
519 "execute_input" => Ok(JupyterMessageContent::ExecuteInput(serde_json::from_value(
520 content,
521 )?)),
522
523 "execute_reply" => Ok(JupyterMessageContent::ExecuteReply(serde_json::from_value(
524 content,
525 )?)),
526 "execute_request" => Ok(JupyterMessageContent::ExecuteRequest(
527 serde_json::from_value(content)?,
528 )),
529
530 "execute_result" => Ok(JupyterMessageContent::ExecuteResult(
531 serde_json::from_value(content)?,
532 )),
533
534 "history_reply" => Ok(JupyterMessageContent::HistoryReply(serde_json::from_value(
535 content,
536 )?)),
537 "history_request" => Ok(JupyterMessageContent::HistoryRequest(
538 serde_json::from_value(content)?,
539 )),
540
541 "input_reply" => Ok(JupyterMessageContent::InputReply(serde_json::from_value(
542 content,
543 )?)),
544 "input_request" => Ok(JupyterMessageContent::InputRequest(serde_json::from_value(
545 content,
546 )?)),
547
548 "inspect_reply" => Ok(JupyterMessageContent::InspectReply(serde_json::from_value(
549 content,
550 )?)),
551 "inspect_request" => Ok(JupyterMessageContent::InspectRequest(
552 serde_json::from_value(content)?,
553 )),
554
555 "interrupt_reply" => Ok(JupyterMessageContent::InterruptReply(
556 serde_json::from_value(content)?,
557 )),
558 "interrupt_request" => Ok(JupyterMessageContent::InterruptRequest(
559 serde_json::from_value(content)?,
560 )),
561
562 "is_complete_reply" => Ok(JupyterMessageContent::IsCompleteReply(
563 serde_json::from_value(content)?,
564 )),
565 "is_complete_request" => Ok(JupyterMessageContent::IsCompleteRequest(
566 serde_json::from_value(content)?,
567 )),
568
569 "kernel_info_reply" => Ok(JupyterMessageContent::KernelInfoReply(
570 serde_json::from_value(content)?,
571 )),
572 "kernel_info_request" => Ok(JupyterMessageContent::KernelInfoRequest(
573 serde_json::from_value(content)?,
574 )),
575
576 "shutdown_reply" => Ok(JupyterMessageContent::ShutdownReply(
577 serde_json::from_value(content)?,
578 )),
579 "shutdown_request" => Ok(JupyterMessageContent::ShutdownRequest(
580 serde_json::from_value(content)?,
581 )),
582
583 "status" => Ok(JupyterMessageContent::Status(serde_json::from_value(
584 content,
585 )?)),
586
587 "stream" => Ok(JupyterMessageContent::StreamContent(
588 serde_json::from_value(content)?,
589 )),
590
591 "update_display_data" => Ok(JupyterMessageContent::UpdateDisplayData(
592 serde_json::from_value(content)?,
593 )),
594
595 _ => Ok(JupyterMessageContent::UnknownMessage(UnknownMessage {
596 msg_type: msg_type.to_string(),
597 content,
598 })),
599 }
600 }
601}
602
603macro_rules! impl_message_traits {
604 ($($name:ident),*) => {
605 $(
606 impl $name {
607 #[doc = concat!("Create a new `JupyterMessage`, assigning the parent for a `", stringify!($name), "` message.\n")]
608 #[doc = concat!("use jupyter_protocol::", stringify!($name), ";\n")]
616 #[doc = concat!("let child_message = ", stringify!($name), "{\n")]
623 #[must_use]
630 pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
631 JupyterMessage::new(self.clone(), Some(parent))
632 }
633 }
634
635 impl From<$name> for JupyterMessage {
636 #[doc(hidden)]
637 #[doc = concat!("Create a new `JupyterMessage` for a `", stringify!($name), "`.\n\n")]
638 #[must_use]
641 fn from(content: $name) -> Self {
642 JupyterMessage::new(content, None)
643 }
644 }
645
646 impl From<$name> for JupyterMessageContent {
647 #[doc = concat!("Create a new `JupyterMessageContent` for a `", stringify!($name), "`.\n\n")]
648 #[must_use]
649 fn from(content: $name) -> Self {
650 JupyterMessageContent::$name(content)
651 }
652 }
653 )*
654 };
655}
656
657impl From<JupyterMessageContent> for JupyterMessage {
658 fn from(content: JupyterMessageContent) -> Self {
659 JupyterMessage::new(content, None)
660 }
661}
662
663impl_message_traits!(
664 ClearOutput,
665 CommClose,
666 CommInfoReply,
667 CommInfoRequest,
668 CommMsg,
669 CommOpen,
670 CompleteReply,
671 CompleteRequest,
672 DebugReply,
673 DebugRequest,
674 DisplayData,
675 ErrorOutput,
676 ExecuteInput,
677 ExecuteReply,
678 ExecuteRequest,
679 ExecuteResult,
680 HistoryReply,
681 InputReply,
683 InputRequest,
684 InspectReply,
685 InspectRequest,
686 InterruptReply,
687 InterruptRequest,
688 IsCompleteReply,
689 IsCompleteRequest,
690 KernelInfoRequest,
692 ShutdownReply,
693 ShutdownRequest,
694 Status,
695 StreamContent,
696 UpdateDisplayData,
697 UnknownMessage
698);
699
700impl KernelInfoReply {
702 pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
703 JupyterMessage::new(
704 JupyterMessageContent::KernelInfoReply(Box::new(self.clone())),
705 Some(parent),
706 )
707 }
708}
709
710impl From<KernelInfoReply> for JupyterMessage {
711 fn from(content: KernelInfoReply) -> Self {
712 JupyterMessage::new(
713 JupyterMessageContent::KernelInfoReply(Box::new(content)),
714 None,
715 )
716 }
717}
718
719impl From<KernelInfoReply> for JupyterMessageContent {
720 fn from(content: KernelInfoReply) -> Self {
721 JupyterMessageContent::KernelInfoReply(Box::new(content))
722 }
723}
724
725impl HistoryRequest {
726 #[must_use]
752 pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
753 JupyterMessage::new(self.clone(), Some(parent))
754 }
755}
756
757impl From<HistoryRequest> for JupyterMessage {
758 #[doc(hidden)]
759 #[must_use]
763 fn from(content: HistoryRequest) -> Self {
764 JupyterMessage::new(content, None)
765 }
766}
767
768impl From<HistoryRequest> for JupyterMessageContent {
769 #[must_use]
771 fn from(content: HistoryRequest) -> Self {
772 JupyterMessageContent::HistoryRequest(content)
773 }
774}
775
776#[derive(Serialize, Deserialize, Debug, Clone)]
791pub struct UnknownMessage {
792 #[serde(skip_serializing, skip_deserializing)]
793 pub msg_type: String,
794 #[serde(flatten)]
795 pub content: Value,
796}
797impl Default for UnknownMessage {
798 fn default() -> Self {
799 Self {
800 msg_type: "unknown".to_string(),
801 content: Value::Null,
802 }
803 }
804}
805
806impl UnknownMessage {
807 pub fn reply(&self, content: serde_json::Value) -> JupyterMessageContent {
811 JupyterMessageContent::UnknownMessage(UnknownMessage {
812 msg_type: self.msg_type.replace("_request", "_reply"),
813 content,
814 })
815 }
816}
817
818#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
820#[serde(rename_all = "lowercase")]
821pub enum ReplyStatus {
822 #[default]
823 Ok,
824 Error,
825 Aborted,
826}
827
828#[derive(Serialize, Deserialize, Debug, Clone, Default)]
829pub struct ReplyError {
830 pub ename: String,
831 pub evalue: String,
832 pub traceback: Vec<String>,
833}
834
835#[derive(Serialize, Deserialize, Debug, Clone, Default)]
837pub struct ClearOutput {
838 pub wait: bool,
842}
843
844#[derive(Serialize, Deserialize, Debug, Clone)]
848pub struct ExecuteRequest {
849 pub code: String,
850 pub silent: bool,
851 pub store_history: bool,
852 #[serde(serialize_with = "serialize_user_expressions")]
853 pub user_expressions: Option<HashMap<String, String>>,
854 #[serde(default = "default_allow_stdin")]
855 pub allow_stdin: bool,
856 #[serde(default = "default_stop_on_error")]
857 pub stop_on_error: bool,
858}
859
860fn serialize_user_expressions<S>(
864 user_expressions: &Option<HashMap<String, String>>,
865 serializer: S,
866) -> Result<S::Ok, S::Error>
867where
868 S: serde::Serializer,
869{
870 match user_expressions {
871 Some(user_expressions) => user_expressions.serialize(serializer),
872 None => serde_json::Map::new().serialize(serializer),
873 }
874}
875
876fn default_allow_stdin() -> bool {
877 false
878}
879
880fn default_stop_on_error() -> bool {
881 true
882}
883
884impl ExecuteRequest {
885 pub fn new(code: String) -> Self {
886 Self {
887 code,
888 ..Default::default()
889 }
890 }
891}
892
893impl Default for ExecuteRequest {
894 fn default() -> Self {
895 Self {
896 code: "".to_string(),
897 silent: false,
898 store_history: true,
899 user_expressions: None,
900 allow_stdin: false,
901 stop_on_error: true,
902 }
903 }
904}
905
906#[derive(Serialize, Deserialize, Debug, Clone)]
914pub struct ExecuteReply {
915 #[serde(default)]
916 pub status: ReplyStatus,
917 pub execution_count: ExecutionCount,
918
919 #[serde(default)]
920 pub payload: Vec<Payload>,
921 pub user_expressions: Option<HashMap<String, String>>,
922
923 #[serde(flatten, skip_serializing_if = "Option::is_none")]
924 pub error: Option<Box<ReplyError>>,
925}
926impl Default for ExecuteReply {
927 fn default() -> Self {
928 Self {
929 status: ReplyStatus::Ok,
930 execution_count: ExecutionCount::new(0),
931 payload: Vec::new(),
932 user_expressions: None,
933 error: None,
934 }
935 }
936}
937
938#[derive(Serialize, Deserialize, Debug, Clone)]
943#[serde(rename_all = "snake_case")]
944#[serde(tag = "source")]
945pub enum Payload {
946 Page {
947 data: Media,
948 start: usize,
949 },
950 SetNextInput {
951 text: String,
952 replace: bool,
953 },
954 EditMagic {
955 filename: String,
956 line_number: usize,
957 },
958 AskExit {
959 keepkernel: bool,
961 },
962}
963
964#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
968pub struct KernelInfoRequest {}
969
970#[derive(Serialize, Deserialize, Debug, Clone)]
974pub struct KernelInfoReply {
975 pub status: ReplyStatus,
976 pub protocol_version: String,
977 pub implementation: String,
978 pub implementation_version: String,
979 pub language_info: LanguageInfo,
980 pub banner: String,
981 pub help_links: Vec<HelpLink>,
982 #[serde(default = "default_debugger")]
983 pub debugger: bool,
984 #[serde(flatten, skip_serializing_if = "Option::is_none")]
985 pub error: Option<Box<ReplyError>>,
986}
987
988fn default_debugger() -> bool {
989 false
990}
991
992#[derive(Serialize, Deserialize, Debug, Clone)]
993#[serde(untagged)]
994pub enum CodeMirrorMode {
995 Simple(String),
996 CustomMode { name: String, version: usize },
997}
998
999#[derive(Serialize, Deserialize, Debug, Clone)]
1000pub struct CodeMirrorModeObject {
1001 pub name: String,
1002 pub version: usize,
1003}
1004
1005impl CodeMirrorMode {
1006 pub fn typescript() -> Self {
1007 Self::Simple("typescript".to_string())
1008 }
1009
1010 pub fn python() -> Self {
1011 Self::Simple("python".to_string())
1012 }
1013
1014 pub fn ipython_code_mirror_mode() -> Self {
1015 Self::CustomMode {
1016 name: "ipython".to_string(),
1017 version: 3,
1018 }
1019 }
1020}
1021
1022#[derive(Serialize, Deserialize, Debug, Clone)]
1023pub struct LanguageInfo {
1024 pub name: String,
1025 pub version: String,
1026 #[serde(skip_serializing_if = "Option::is_none")]
1027 pub mimetype: Option<String>,
1028 #[serde(skip_serializing_if = "Option::is_none")]
1029 pub file_extension: Option<String>,
1030 #[serde(skip_serializing_if = "Option::is_none")]
1031 pub pygments_lexer: Option<String>,
1032 #[serde(skip_serializing_if = "Option::is_none")]
1033 pub codemirror_mode: Option<CodeMirrorMode>,
1034 #[serde(skip_serializing_if = "Option::is_none")]
1035 pub nbconvert_exporter: Option<String>,
1036}
1037
1038#[derive(Serialize, Deserialize, Debug, Clone)]
1039pub struct HelpLink {
1040 pub text: String,
1041 pub url: String,
1042}
1043
1044#[derive(Serialize, Deserialize, Debug, Clone)]
1045pub enum Stdio {
1046 #[serde(rename = "stdout")]
1047 Stdout,
1048 #[serde(rename = "stderr")]
1049 Stderr,
1050}
1051
1052#[derive(Serialize, Deserialize, Debug, Clone)]
1094pub struct StreamContent {
1095 pub name: Stdio,
1096 pub text: String,
1097}
1098impl Default for StreamContent {
1099 fn default() -> Self {
1100 Self {
1101 name: Stdio::Stdout,
1102 text: String::new(),
1103 }
1104 }
1105}
1106
1107impl StreamContent {
1108 pub fn stdout(text: &str) -> Self {
1109 Self {
1110 name: Stdio::Stdout,
1111 text: text.to_string(),
1112 }
1113 }
1114
1115 pub fn stderr(text: &str) -> Self {
1116 Self {
1117 name: Stdio::Stderr,
1118 text: text.to_string(),
1119 }
1120 }
1121}
1122
1123#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1125pub struct Transient {
1126 #[serde(skip_serializing_if = "Option::is_none")]
1127 pub display_id: Option<String>,
1128}
1129
1130#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1170pub struct DisplayData {
1171 pub data: Media,
1172 pub metadata: serde_json::Map<String, Value>,
1173 #[serde(default, skip_serializing_if = "Option::is_none")]
1174 pub transient: Option<Transient>,
1175}
1176
1177impl DisplayData {
1178 pub fn new(data: Media) -> Self {
1179 Self {
1180 data,
1181 metadata: Default::default(),
1182 transient: Default::default(),
1183 }
1184 }
1185}
1186
1187impl From<Vec<MediaType>> for DisplayData {
1188 fn from(content: Vec<MediaType>) -> Self {
1189 Self::new(Media::new(content))
1190 }
1191}
1192
1193impl From<MediaType> for DisplayData {
1194 fn from(content: MediaType) -> Self {
1195 Self::new(Media::new(vec![content]))
1196 }
1197}
1198
1199#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1202pub struct UpdateDisplayData {
1203 pub data: Media,
1204 #[serde(default)]
1205 pub metadata: serde_json::Map<String, Value>,
1206 pub transient: Transient,
1207}
1208
1209impl UpdateDisplayData {
1210 pub fn new(data: Media, display_id: &str) -> Self {
1211 Self {
1212 data,
1213 metadata: Default::default(),
1214 transient: Transient {
1215 display_id: Some(display_id.to_string()),
1216 },
1217 }
1218 }
1219}
1220
1221#[derive(Serialize, Deserialize, Debug, Clone)]
1227pub struct ExecuteInput {
1228 pub code: String,
1229 pub execution_count: ExecutionCount,
1230}
1231impl Default for ExecuteInput {
1232 fn default() -> Self {
1233 Self {
1234 code: String::new(),
1235 execution_count: ExecutionCount::new(0),
1236 }
1237 }
1238}
1239
1240#[derive(Serialize, Deserialize, Debug, Clone)]
1264pub struct ExecuteResult {
1265 pub execution_count: ExecutionCount,
1266 pub data: Media,
1267 #[serde(default)]
1268 pub metadata: serde_json::Map<String, Value>,
1269 pub transient: Option<Transient>,
1270}
1271impl Default for ExecuteResult {
1272 fn default() -> Self {
1273 Self {
1274 execution_count: ExecutionCount::new(0),
1275 data: Media::default(),
1276 metadata: serde_json::Map::new(),
1277 transient: None,
1278 }
1279 }
1280}
1281
1282impl ExecuteResult {
1283 pub fn new(execution_count: ExecutionCount, data: Media) -> Self {
1284 Self {
1285 execution_count,
1286 data,
1287 metadata: Default::default(),
1288 transient: None,
1289 }
1290 }
1291}
1292
1293impl From<(ExecutionCount, Vec<MediaType>)> for ExecuteResult {
1294 fn from((execution_count, content): (ExecutionCount, Vec<MediaType>)) -> Self {
1295 Self::new(execution_count, content.into())
1296 }
1297}
1298
1299impl From<(ExecutionCount, MediaType)> for ExecuteResult {
1300 fn from((execution_count, content): (ExecutionCount, MediaType)) -> Self {
1301 Self::new(execution_count, content.into())
1302 }
1303}
1304
1305#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1311pub struct ErrorOutput {
1312 pub ename: String,
1313 pub evalue: String,
1314 pub traceback: Vec<String>,
1315}
1316
1317#[derive(Serialize, Deserialize, Debug, Clone)]
1345pub struct CommOpen {
1346 pub comm_id: CommId,
1347 pub target_name: String,
1348 pub data: serde_json::Map<String, Value>,
1349 #[serde(skip_serializing_if = "Option::is_none")]
1350 pub target_module: Option<String>,
1351}
1352impl Default for CommOpen {
1353 fn default() -> Self {
1354 Self {
1355 comm_id: CommId("".to_string()),
1356 target_name: String::new(),
1357 data: serde_json::Map::new(),
1358 target_module: None,
1359 }
1360 }
1361}
1362
1363#[derive(Serialize, Deserialize, Debug, Clone)]
1382pub struct CommMsg {
1383 pub comm_id: CommId,
1384 pub data: serde_json::Map<String, Value>,
1385}
1386impl Default for CommMsg {
1387 fn default() -> Self {
1388 Self {
1389 comm_id: CommId("".to_string()),
1390 data: serde_json::Map::new(),
1391 }
1392 }
1393}
1394
1395#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1396pub struct CommInfoRequest {
1397 pub target_name: Option<String>,
1398}
1399
1400#[derive(Eq, Hash, PartialEq, Serialize, Deserialize, Debug, Clone)]
1401pub struct CommId(pub String);
1402
1403impl From<CommId> for String {
1404 fn from(comm_id: CommId) -> Self {
1405 comm_id.0
1406 }
1407}
1408
1409impl From<String> for CommId {
1410 fn from(comm_id: String) -> Self {
1411 Self(comm_id)
1412 }
1413}
1414
1415#[derive(Serialize, Deserialize, Debug, Clone)]
1416pub struct CommInfo {
1417 pub target_name: String,
1418}
1419
1420#[derive(Serialize, Deserialize, Debug, Clone)]
1421pub struct CommInfoReply {
1422 #[serde(default)]
1423 pub status: ReplyStatus,
1424 pub comms: HashMap<CommId, CommInfo>,
1425 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1427 pub error: Option<Box<ReplyError>>,
1428}
1429impl Default for CommInfoReply {
1430 fn default() -> Self {
1431 Self {
1432 status: ReplyStatus::Ok,
1433 comms: HashMap::new(),
1434 error: None,
1435 }
1436 }
1437}
1438
1439#[derive(Serialize, Deserialize, Debug, Clone)]
1444pub struct CommClose {
1445 pub comm_id: CommId,
1446 pub data: serde_json::Map<String, Value>,
1447}
1448impl Default for CommClose {
1449 fn default() -> Self {
1450 Self {
1451 comm_id: CommId("".to_string()),
1452 data: serde_json::Map::new(),
1453 }
1454 }
1455}
1456
1457#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1458pub struct ShutdownRequest {
1465 pub restart: bool,
1466}
1467
1468#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1469pub struct InterruptRequest {}
1477
1478#[derive(Serialize, Deserialize, Debug, Clone)]
1479pub struct InterruptReply {
1486 pub status: ReplyStatus,
1487
1488 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1489 pub error: Option<Box<ReplyError>>,
1490}
1491
1492impl Default for InterruptReply {
1493 fn default() -> Self {
1494 Self::new()
1495 }
1496}
1497
1498impl InterruptReply {
1499 pub fn new() -> Self {
1500 Self {
1501 status: ReplyStatus::Ok,
1502 error: None,
1503 }
1504 }
1505}
1506
1507#[derive(Serialize, Deserialize, Debug, Clone)]
1508pub struct ShutdownReply {
1515 pub restart: bool,
1516 pub status: ReplyStatus,
1517
1518 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1519 pub error: Option<Box<ReplyError>>,
1520}
1521impl Default for ShutdownReply {
1522 fn default() -> Self {
1523 Self {
1524 restart: false,
1525 status: ReplyStatus::Ok,
1526 error: None,
1527 }
1528 }
1529}
1530
1531#[derive(Serialize, Deserialize, Debug, Clone)]
1532pub struct InputRequest {
1539 pub prompt: String,
1540 pub password: bool,
1541}
1542impl Default for InputRequest {
1543 fn default() -> Self {
1544 Self {
1545 prompt: "> ".to_string(),
1546 password: false,
1547 }
1548 }
1549}
1550
1551#[derive(Serialize, Deserialize, Debug, Clone)]
1552pub struct InputReply {
1559 pub value: String,
1560
1561 pub status: ReplyStatus,
1562 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1563 pub error: Option<Box<ReplyError>>,
1564}
1565impl Default for InputReply {
1566 fn default() -> Self {
1567 Self {
1568 value: String::new(),
1569 status: ReplyStatus::Ok,
1570 error: None,
1571 }
1572 }
1573}
1574
1575#[derive(Serialize, Deserialize, Debug, Clone)]
1581pub struct InspectRequest {
1582 pub code: String,
1585 pub cursor_pos: usize,
1587 pub detail_level: Option<usize>,
1592}
1593impl Default for InspectRequest {
1594 fn default() -> Self {
1595 Self {
1596 code: String::new(),
1597 cursor_pos: 0,
1598 detail_level: Some(0),
1599 }
1600 }
1601}
1602
1603#[derive(Serialize, Deserialize, Debug, Clone)]
1604pub struct InspectReply {
1605 pub found: bool,
1606 pub data: Media,
1607 pub metadata: serde_json::Map<String, Value>,
1608 #[serde(default)]
1609 pub status: ReplyStatus,
1610 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1611 pub error: Option<Box<ReplyError>>,
1612}
1613impl Default for InspectReply {
1614 fn default() -> Self {
1615 Self {
1616 found: false,
1617 data: Media::default(),
1618 metadata: serde_json::Map::new(),
1619 status: ReplyStatus::Ok,
1620 error: None,
1621 }
1622 }
1623}
1624
1625#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1629pub struct CompleteRequest {
1630 pub code: String,
1631 pub cursor_pos: usize,
1632}
1633
1634#[derive(Serialize, Deserialize, Debug, Clone)]
1638pub struct CompleteReply {
1639 pub matches: Vec<String>,
1640 pub cursor_start: usize,
1641 pub cursor_end: usize,
1642 pub metadata: serde_json::Map<String, Value>,
1643 #[serde(default)]
1644 pub status: ReplyStatus,
1645 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1646 pub error: Option<Box<ReplyError>>,
1647}
1648impl Default for CompleteReply {
1649 fn default() -> Self {
1650 Self {
1651 matches: Vec::new(),
1652 cursor_start: 0,
1653 cursor_end: 0,
1654 metadata: serde_json::Map::new(),
1655 status: ReplyStatus::Ok,
1656 error: None,
1657 }
1658 }
1659}
1660
1661#[derive(Serialize, Deserialize, Debug, Clone)]
1662pub struct DebugRequest {
1663 #[serde(flatten)]
1664 pub content: Value,
1665}
1666impl Default for DebugRequest {
1667 fn default() -> Self {
1668 Self {
1669 content: Value::Null,
1670 }
1671 }
1672}
1673
1674#[derive(Serialize, Deserialize, Debug, Clone)]
1675pub struct DebugReply {
1676 #[serde(flatten)]
1677 pub content: Value,
1678}
1679impl Default for DebugReply {
1680 fn default() -> Self {
1681 Self {
1682 content: Value::Null,
1683 }
1684 }
1685}
1686
1687#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1688#[serde(rename_all = "snake_case")]
1689pub enum IsCompleteReplyStatus {
1690 Incomplete,
1693 Complete,
1695 Invalid,
1697 Unknown,
1702}
1703
1704#[derive(Serialize, Deserialize, Debug, Clone)]
1705pub struct IsCompleteReply {
1706 pub status: IsCompleteReplyStatus,
1709 pub indent: String,
1714}
1715impl Default for IsCompleteReply {
1716 fn default() -> Self {
1717 Self {
1718 status: IsCompleteReplyStatus::Unknown,
1719 indent: String::new(),
1720 }
1721 }
1722}
1723
1724impl IsCompleteReply {
1725 pub fn new(status: IsCompleteReplyStatus, indent: String) -> Self {
1726 Self { status, indent }
1727 }
1728
1729 pub fn incomplete(indent: String) -> Self {
1730 Self::new(IsCompleteReplyStatus::Incomplete, indent)
1731 }
1732
1733 pub fn complete() -> Self {
1734 Self::new(IsCompleteReplyStatus::Complete, String::new())
1735 }
1736
1737 pub fn invalid() -> Self {
1738 Self::new(IsCompleteReplyStatus::Invalid, String::new())
1739 }
1740
1741 pub fn unknown() -> Self {
1742 Self::new(IsCompleteReplyStatus::Unknown, String::new())
1743 }
1744}
1745
1746#[derive(Serialize, Deserialize, Debug, Clone)]
1747#[serde(tag = "hist_access_type")]
1748pub enum HistoryRequest {
1749 #[serde(rename = "range")]
1750 Range {
1751 session: Option<i32>,
1752 start: i32,
1753 stop: i32,
1754 output: bool,
1755 raw: bool,
1756 },
1757 #[serde(rename = "tail")]
1758 Tail { n: i32, output: bool, raw: bool },
1759 #[serde(rename = "search")]
1760 Search {
1761 pattern: String,
1762 unique: bool,
1763 output: bool,
1764 raw: bool,
1765 n: i32,
1766 },
1767}
1768impl Default for HistoryRequest {
1769 fn default() -> Self {
1770 Self::Range {
1771 session: None,
1772 start: 0,
1773 stop: 0,
1774 output: false,
1775 raw: false,
1776 }
1777 }
1778}
1779
1780#[derive(Serialize, Deserialize, Debug, Clone)]
1781#[serde(untagged)]
1782pub enum HistoryEntry {
1783 Input(usize, usize, String),
1786 InputOutput(usize, usize, (String, String)),
1789}
1790
1791#[derive(Serialize, Deserialize, Debug, Clone)]
1795pub struct HistoryReply {
1796 pub history: Vec<HistoryEntry>,
1797
1798 pub status: ReplyStatus,
1799 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1800 pub error: Option<Box<ReplyError>>,
1801}
1802impl Default for HistoryReply {
1803 fn default() -> Self {
1804 Self {
1805 history: Vec::new(),
1806 status: ReplyStatus::Ok,
1807 error: None,
1808 }
1809 }
1810}
1811
1812impl HistoryReply {
1813 pub fn new(history: Vec<HistoryEntry>) -> Self {
1814 Self {
1815 history,
1816 status: ReplyStatus::Ok,
1817 error: None,
1818 }
1819 }
1820}
1821
1822#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1826pub struct IsCompleteRequest {
1827 pub code: String,
1828}
1829
1830#[derive(Debug, Clone, PartialEq)]
1831pub enum ExecutionState {
1832 Unknown,
1833 Starting,
1834 Busy,
1835 Idle,
1836 Restarting,
1837 Terminating,
1838 AutoRestarting,
1839 Dead,
1840 Other(String),
1841}
1842
1843impl ExecutionState {
1844 pub fn as_str(&self) -> &str {
1845 match self {
1846 ExecutionState::Unknown => "unknown",
1847 ExecutionState::Terminating => "terminating",
1848 ExecutionState::AutoRestarting => "autorestarting",
1849 ExecutionState::Dead => "dead",
1850 ExecutionState::Busy => "busy",
1851 ExecutionState::Idle => "idle",
1852 ExecutionState::Starting => "starting",
1853 ExecutionState::Restarting => "restarting",
1854 ExecutionState::Other(s) => s,
1855 }
1856 }
1857}
1858
1859impl serde::Serialize for ExecutionState {
1860 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1861 where
1862 S: serde::Serializer,
1863 {
1864 match self {
1865 ExecutionState::Unknown => serializer.serialize_str("unknown"),
1866 ExecutionState::Terminating => serializer.serialize_str("terminating"),
1867 ExecutionState::AutoRestarting => serializer.serialize_str("autorestarting"),
1868 ExecutionState::Dead => serializer.serialize_str("dead"),
1869 ExecutionState::Busy => serializer.serialize_str("busy"),
1870 ExecutionState::Idle => serializer.serialize_str("idle"),
1871 ExecutionState::Starting => serializer.serialize_str("starting"),
1872 ExecutionState::Restarting => serializer.serialize_str("restarting"),
1873 ExecutionState::Other(s) => serializer.serialize_str(s),
1874 }
1875 }
1876}
1877
1878impl<'de> serde::Deserialize<'de> for ExecutionState {
1879 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1880 where
1881 D: serde::Deserializer<'de>,
1882 {
1883 struct ExecutionStateVisitor;
1884
1885 impl serde::de::Visitor<'_> for ExecutionStateVisitor {
1886 type Value = ExecutionState;
1887
1888 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1889 formatter.write_str("a string representing an execution state")
1890 }
1891 fn visit_str<E>(self, value: &str) -> Result<ExecutionState, E>
1892 where
1893 E: serde::de::Error,
1894 {
1895 match value {
1896 "unknown" => Ok(ExecutionState::Unknown),
1897 "terminating" => Ok(ExecutionState::Terminating),
1898 "autorestarting" => Ok(ExecutionState::AutoRestarting),
1899 "dead" => Ok(ExecutionState::Dead),
1900 "busy" => Ok(ExecutionState::Busy),
1901 "idle" => Ok(ExecutionState::Idle),
1902 "starting" => Ok(ExecutionState::Starting),
1903 "restarting" => Ok(ExecutionState::Restarting),
1904 other => Ok(ExecutionState::Other(other.to_string())),
1905 }
1906 }
1907 }
1908 deserializer.deserialize_str(ExecutionStateVisitor)
1909 }
1910}
1911
1912#[derive(Serialize, Deserialize, Debug, Clone)]
1916pub struct Status {
1917 pub execution_state: ExecutionState,
1918}
1919impl Default for Status {
1920 fn default() -> Self {
1921 Self {
1922 execution_state: ExecutionState::Idle,
1923 }
1924 }
1925}
1926
1927impl Status {
1928 pub fn busy() -> Self {
1929 Self {
1930 execution_state: ExecutionState::Busy,
1931 }
1932 }
1933
1934 pub fn idle() -> Self {
1935 Self {
1936 execution_state: ExecutionState::Idle,
1937 }
1938 }
1939
1940 pub fn starting() -> Self {
1941 Self {
1942 execution_state: ExecutionState::Starting,
1943 }
1944 }
1945
1946 pub fn restarting() -> Self {
1947 Self {
1948 execution_state: ExecutionState::Restarting,
1949 }
1950 }
1951
1952 pub fn other(state: impl Into<String>) -> Self {
1953 Self {
1954 execution_state: ExecutionState::Other(state.into()),
1955 }
1956 }
1957}
1958
1959#[cfg(test)]
1960mod test {
1961 use serde_json::json;
1962
1963 use super::*;
1964
1965 #[test]
1966 fn test_execute_request_serialize() {
1967 let request = ExecuteRequest {
1968 code: "print('Hello, World!')".to_string(),
1969 silent: false,
1970 store_history: true,
1971 user_expressions: Some(HashMap::new()),
1972 allow_stdin: false,
1973 stop_on_error: true,
1974 };
1975 let request_value = serde_json::to_value(request).unwrap();
1976
1977 let expected_request_value = serde_json::json!({
1978 "code": "print('Hello, World!')",
1979 "silent": false,
1980 "store_history": true,
1981 "user_expressions": {},
1982 "allow_stdin": false,
1983 "stop_on_error": true
1984 });
1985
1986 assert_eq!(request_value, expected_request_value);
1987 }
1988
1989 #[test]
1990 fn test_execute_request_user_expressions_serializes_to_empty_dict() {
1991 let request = ExecuteRequest {
1992 code: "print('Hello, World!')".to_string(),
1993 silent: false,
1994 store_history: true,
1995 user_expressions: None,
1996 allow_stdin: false,
1997 stop_on_error: true,
1998 };
1999 let request_value = serde_json::to_value(request).unwrap();
2000
2001 let expected_request_value = serde_json::json!({
2002 "code": "print('Hello, World!')",
2003 "silent": false,
2004 "store_history": true,
2005 "user_expressions": {},
2006 "allow_stdin": false,
2007 "stop_on_error": true
2008 });
2009
2010 assert_eq!(request_value, expected_request_value);
2011 }
2012
2013 #[test]
2014 fn test_into_various() {
2015 let kernel_info_request = KernelInfoRequest {};
2016 let content: JupyterMessageContent = kernel_info_request.clone().into();
2017 let message: JupyterMessage = content.into();
2018 assert!(message.parent_header.is_none());
2019 match message.content {
2020 JupyterMessageContent::KernelInfoRequest(req) => {
2021 assert_eq!(req, kernel_info_request);
2022 }
2023 _ => panic!("Expected KernelInfoRequest"),
2024 }
2025
2026 let kernel_info_request = KernelInfoRequest {};
2027 let message: JupyterMessage = kernel_info_request.clone().into();
2028 assert!(message.parent_header.is_none());
2029 match message.content {
2030 JupyterMessageContent::KernelInfoRequest(req) => {
2031 assert_eq!(req, kernel_info_request);
2032 }
2033 _ => panic!("Expected KernelInfoRequest"),
2034 }
2035 }
2036
2037 #[test]
2038 fn test_default() {
2039 let msg: JupyterMessage = ExecuteRequest {
2040 code: "import this".to_string(),
2041 ..Default::default()
2042 }
2043 .into();
2044
2045 assert_eq!(msg.header.msg_type, "execute_request");
2046 assert_eq!(msg.header.msg_id.len(), 36);
2047
2048 match msg.content {
2049 JupyterMessageContent::ExecuteRequest(req) => {
2050 assert_eq!(req.code, "import this");
2051 assert!(!req.silent);
2052 assert!(req.store_history);
2053 assert_eq!(req.user_expressions, None);
2054 assert!(!req.allow_stdin);
2055 assert!(req.stop_on_error);
2056 }
2057 _ => panic!("Expected ExecuteRequest"),
2058 }
2059 }
2060
2061 #[test]
2062 fn test_deserialize_payload() {
2063 let raw_execute_reply_content = r#"
2064 {
2065 "status": "ok",
2066 "execution_count": 1,
2067 "payload": [{
2068 "source": "page",
2069 "data": {
2070 "text/html": "<h1>Hello</h1>",
2071 "text/plain": "Hello"
2072 },
2073 "start": 0
2074 }],
2075 "user_expressions": {}
2076 }
2077 "#;
2078
2079 let execute_reply: ExecuteReply = serde_json::from_str(raw_execute_reply_content).unwrap();
2080
2081 assert_eq!(execute_reply.status, ReplyStatus::Ok);
2082 assert_eq!(execute_reply.execution_count, ExecutionCount::new(1));
2083
2084 let payload = execute_reply.payload.clone();
2085
2086 assert_eq!(payload.len(), 1);
2087 let payload = payload.first().unwrap();
2088
2089 let media = match payload {
2090 Payload::Page { data, .. } => data,
2091 _ => panic!("Expected Page payload type"),
2092 };
2093
2094 let media = serde_json::to_value(media).unwrap();
2095
2096 let expected_media = serde_json::json!({
2097 "text/html": "<h1>Hello</h1>",
2098 "text/plain": "Hello"
2099 });
2100
2101 assert_eq!(media, expected_media);
2102 }
2103
2104 #[test]
2105 pub fn test_display_data_various_data() {
2106 let display_data = DisplayData {
2107 data: serde_json::from_value(json!({
2108 "text/plain": "Hello, World!",
2109 "text/html": "<h1>Hello, World!</h1>",
2110 "application/json": {
2111 "hello": "world",
2112 "foo": "bar",
2113 "ok": [1, 2, 3],
2114 }
2115 }))
2116 .unwrap(),
2117 ..Default::default()
2118 };
2119
2120 let display_data_value = serde_json::to_value(display_data).unwrap();
2121
2122 let expected_display_data_value = serde_json::json!({
2123 "data": {
2124 "text/plain": "Hello, World!",
2125 "text/html": "<h1>Hello, World!</h1>",
2126 "application/json": {
2127 "hello": "world",
2128 "foo": "bar",
2129 "ok": [1, 2, 3]
2130 }
2131 },
2132 "metadata": {}
2133 });
2134
2135 assert_eq!(display_data_value, expected_display_data_value);
2136 }
2137
2138 use std::mem::size_of;
2139
2140 macro_rules! size_of_variant {
2141 ($variant:ty) => {
2142 let size = size_of::<$variant>();
2143 println!("The size of {} is: {} bytes", stringify!($variant), size);
2144
2145 assert!(size <= 96);
2146 };
2147 }
2148
2149 #[test]
2150 fn test_enum_variant_sizes() {
2151 size_of_variant!(ClearOutput);
2152 size_of_variant!(CommClose);
2153 size_of_variant!(CommInfoReply);
2154 size_of_variant!(CommInfoRequest);
2155 size_of_variant!(CommMsg);
2156 size_of_variant!(CommOpen);
2157 size_of_variant!(CompleteReply);
2158 size_of_variant!(CompleteRequest);
2159 size_of_variant!(DebugReply);
2160 size_of_variant!(DebugRequest);
2161 size_of_variant!(DisplayData);
2162 size_of_variant!(ErrorOutput);
2163 size_of_variant!(ExecuteInput);
2164 size_of_variant!(ExecuteReply);
2165 size_of_variant!(ExecuteRequest);
2166 size_of_variant!(ExecuteResult);
2167 size_of_variant!(HistoryReply);
2168 size_of_variant!(HistoryRequest);
2169 size_of_variant!(InputReply);
2170 size_of_variant!(InputRequest);
2171 size_of_variant!(InspectReply);
2172 size_of_variant!(InspectRequest);
2173 size_of_variant!(InterruptReply);
2174 size_of_variant!(InterruptRequest);
2175 size_of_variant!(IsCompleteReply);
2176 size_of_variant!(IsCompleteRequest);
2177 size_of_variant!(Box<KernelInfoReply>);
2178 size_of_variant!(KernelInfoRequest);
2179 size_of_variant!(ShutdownReply);
2180 size_of_variant!(ShutdownRequest);
2181 size_of_variant!(Status);
2182 size_of_variant!(StreamContent);
2183 size_of_variant!(UnknownMessage);
2184 size_of_variant!(UpdateDisplayData);
2185 }
2186
2187 #[test]
2188 fn test_jupyter_message_content_enum_size() {
2189 let size = size_of::<JupyterMessageContent>();
2190 println!("The size of JupyterMessageContent is: {}", size);
2191 assert!(size > 0);
2192 assert!(size <= 104);
2193 }
2194
2195 #[test]
2196 fn test_jupyter_message_parent_header_serializes_to_empty_dict() {
2197 let request = ExecuteRequest {
2198 code: "1 + 1".to_string(),
2199 ..Default::default()
2200 };
2201 let message = JupyterMessage::from(request);
2202
2203 let serialized_message = serde_json::to_value(message).unwrap();
2204
2205 let parent_header = serialized_message.get("parent_header").unwrap();
2207 assert!(parent_header.is_object());
2208 assert!(parent_header.as_object().unwrap().is_empty());
2209 }
2210
2211 #[test]
2212 fn test_user_expressions_serialization() {
2213 let request = ExecuteRequest {
2214 code: "pass".to_string(),
2215 silent: false,
2216 store_history: true,
2217 user_expressions: Some(HashMap::from([(
2218 String::from("expression"),
2219 String::from("42 + 7"),
2220 )])),
2221 allow_stdin: false,
2222 stop_on_error: true,
2223 };
2224 let request_value = serde_json::to_value(request.clone()).unwrap();
2225
2226 let expected_request_value = serde_json::json!({
2227 "code": "pass",
2228 "silent": false,
2229 "store_history": true,
2230 "user_expressions": {"expression": "42 + 7"},
2231 "allow_stdin": false,
2232 "stop_on_error": true
2233 });
2234
2235 assert_eq!(request_value, expected_request_value);
2236
2237 let deserialized_request: ExecuteRequest = serde_json::from_value(request_value).unwrap();
2238 assert_eq!(
2239 deserialized_request.user_expressions,
2240 request.user_expressions
2241 );
2242 }
2243
2244 #[test]
2245 fn test_jupyter_message_parent_header_deserialize() {
2246 let msg = r#"
2247 {
2248 "buffers": [],
2249 "channel": "shell",
2250 "content": {},
2251 "header": {
2252 "date": "2025-05-14T14:32:23.490Z",
2253 "msg_id": "44bd6b44-78a1-4892-87df-c0861a005d56",
2254 "msg_type": "kernel_info_request",
2255 "session": "b75bddaa-6d69-4340-ba13-81516192370e",
2256 "username": "",
2257 "version": "5.2"
2258 },
2259 "metadata": {},
2260 "parent_header": {
2261 "date": "2025-05-14T14:32:23.490Z",
2262 "msg_id": "2aaf8916-6b83-4f5a-80dd-633e94f5d8e1",
2263 "msg_type": "kernel_info_request",
2264 "session": "e2a3165d-76a8-4fef-850f-712102589660",
2265 "username": "",
2266 "version": "5.2"
2267 }
2268}
2269 "#;
2270
2271 let message: JupyterMessage = serde_json::from_str(msg).unwrap();
2272 assert!(message.parent_header.is_some());
2273 assert_eq!(
2274 message.parent_header.as_ref().unwrap().msg_type,
2275 "kernel_info_request"
2276 );
2277 assert_eq!(
2278 message.parent_header.as_ref().unwrap().msg_id,
2279 "2aaf8916-6b83-4f5a-80dd-633e94f5d8e1"
2280 );
2281 assert_eq!(
2282 message.header.msg_id,
2283 "44bd6b44-78a1-4892-87df-c0861a005d56"
2284 );
2285 }
2286
2287 #[test]
2288 fn test_jupyter_message_empty_parent_header_deserialize() {
2289 let msg = r#"
2290 {
2291 "buffers": [],
2292 "channel": "shell",
2293 "content": {},
2294 "header": {
2295 "date": "2025-05-14T14:32:23.490Z",
2296 "msg_id": "44bd6b44-78a1-4892-87df-c0861a005d56",
2297 "msg_type": "kernel_info_request",
2298 "session": "b75bddaa-6d69-4340-ba13-81516192370e",
2299 "username": "",
2300 "version": "5.2"
2301 },
2302 "metadata": {},
2303 "parent_header": {}
2304}
2305 "#;
2306
2307 let message: JupyterMessage = serde_json::from_str(msg).unwrap();
2308 assert!(message.parent_header.is_none());
2309 assert_eq!(message.header.msg_type, "kernel_info_request");
2310 assert_eq!(
2311 message.header.msg_id,
2312 "44bd6b44-78a1-4892-87df-c0861a005d56"
2313 );
2314 }
2315
2316 #[test]
2317 fn test_execution_state_other_serde() {
2318 let json = r#""busy""#;
2319 let state: ExecutionState = serde_json::from_str(json).unwrap();
2320 assert_eq!(state, ExecutionState::Busy);
2321 let serialized = serde_json::to_string(&state).unwrap();
2322 assert_eq!(serialized, "\"busy\"");
2323
2324 let state = ExecutionState::Idle;
2325 let serialized = serde_json::to_string(&state).unwrap();
2326 assert_eq!(serialized, "\"idle\"");
2327 let state: ExecutionState = serde_json::from_str(&serialized).unwrap();
2328 assert_eq!(state, ExecutionState::Idle);
2329
2330 let json = r#""disconnected""#;
2331 let state: ExecutionState = serde_json::from_str(json).unwrap();
2332 assert_eq!(state, ExecutionState::Other("disconnected".to_string()));
2333 let serialized = serde_json::to_string(&state).unwrap();
2334 assert_eq!(serialized, "\"disconnected\"");
2335 }
2336}