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 fn from(content: $name) -> Self {
641 JupyterMessage::new(content, None)
642 }
643 }
644
645 impl From<$name> for JupyterMessageContent {
646 #[doc = concat!("Create a new `JupyterMessageContent` for a `", stringify!($name), "`.\n\n")]
647 fn from(content: $name) -> Self {
648 JupyterMessageContent::$name(content)
649 }
650 }
651 )*
652 };
653}
654
655impl From<JupyterMessageContent> for JupyterMessage {
656 fn from(content: JupyterMessageContent) -> Self {
657 JupyterMessage::new(content, None)
658 }
659}
660
661impl_message_traits!(
662 ClearOutput,
663 CommClose,
664 CommInfoReply,
665 CommInfoRequest,
666 CommMsg,
667 CommOpen,
668 CompleteReply,
669 CompleteRequest,
670 DebugReply,
671 DebugRequest,
672 DisplayData,
673 ErrorOutput,
674 ExecuteInput,
675 ExecuteReply,
676 ExecuteRequest,
677 ExecuteResult,
678 HistoryReply,
679 InputReply,
681 InputRequest,
682 InspectReply,
683 InspectRequest,
684 InterruptReply,
685 InterruptRequest,
686 IsCompleteReply,
687 IsCompleteRequest,
688 KernelInfoRequest,
690 ShutdownReply,
691 ShutdownRequest,
692 Status,
693 StreamContent,
694 UpdateDisplayData,
695 UnknownMessage
696);
697
698impl KernelInfoReply {
700 pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
701 JupyterMessage::new(
702 JupyterMessageContent::KernelInfoReply(Box::new(self.clone())),
703 Some(parent),
704 )
705 }
706}
707
708impl From<KernelInfoReply> for JupyterMessage {
709 fn from(content: KernelInfoReply) -> Self {
710 JupyterMessage::new(
711 JupyterMessageContent::KernelInfoReply(Box::new(content)),
712 None,
713 )
714 }
715}
716
717impl From<KernelInfoReply> for JupyterMessageContent {
718 fn from(content: KernelInfoReply) -> Self {
719 JupyterMessageContent::KernelInfoReply(Box::new(content))
720 }
721}
722
723impl HistoryRequest {
724 #[must_use]
750 pub fn as_child_of(&self, parent: &JupyterMessage) -> JupyterMessage {
751 JupyterMessage::new(self.clone(), Some(parent))
752 }
753}
754
755impl From<HistoryRequest> for JupyterMessage {
756 #[doc(hidden)]
757 fn from(content: HistoryRequest) -> Self {
761 JupyterMessage::new(content, None)
762 }
763}
764
765impl From<HistoryRequest> for JupyterMessageContent {
766 fn from(content: HistoryRequest) -> Self {
768 JupyterMessageContent::HistoryRequest(content)
769 }
770}
771
772#[derive(Serialize, Deserialize, Debug, Clone)]
787pub struct UnknownMessage {
788 #[serde(skip_serializing, skip_deserializing)]
789 pub msg_type: String,
790 #[serde(flatten)]
791 pub content: Value,
792}
793impl Default for UnknownMessage {
794 fn default() -> Self {
795 Self {
796 msg_type: "unknown".to_string(),
797 content: Value::Null,
798 }
799 }
800}
801
802impl UnknownMessage {
803 pub fn reply(&self, content: serde_json::Value) -> JupyterMessageContent {
807 JupyterMessageContent::UnknownMessage(UnknownMessage {
808 msg_type: self.msg_type.replace("_request", "_reply"),
809 content,
810 })
811 }
812}
813
814#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
816#[serde(rename_all = "lowercase")]
817pub enum ReplyStatus {
818 #[default]
819 Ok,
820 Error,
821 Aborted,
822}
823
824#[derive(Serialize, Deserialize, Debug, Clone, Default)]
825pub struct ReplyError {
826 pub ename: String,
827 pub evalue: String,
828 pub traceback: Vec<String>,
829}
830
831#[derive(Serialize, Deserialize, Debug, Clone, Default)]
833pub struct ClearOutput {
834 pub wait: bool,
838}
839
840#[derive(Serialize, Deserialize, Debug, Clone)]
844pub struct ExecuteRequest {
845 pub code: String,
846 pub silent: bool,
847 pub store_history: bool,
848 #[serde(serialize_with = "serialize_user_expressions")]
849 pub user_expressions: Option<HashMap<String, String>>,
850 #[serde(default = "default_allow_stdin")]
851 pub allow_stdin: bool,
852 #[serde(default = "default_stop_on_error")]
853 pub stop_on_error: bool,
854}
855
856fn serialize_user_expressions<S>(
860 user_expressions: &Option<HashMap<String, String>>,
861 serializer: S,
862) -> Result<S::Ok, S::Error>
863where
864 S: serde::Serializer,
865{
866 match user_expressions {
867 Some(user_expressions) => user_expressions.serialize(serializer),
868 None => serde_json::Map::new().serialize(serializer),
869 }
870}
871
872fn default_allow_stdin() -> bool {
873 false
874}
875
876fn default_stop_on_error() -> bool {
877 true
878}
879
880impl ExecuteRequest {
881 pub fn new(code: String) -> Self {
882 Self {
883 code,
884 ..Default::default()
885 }
886 }
887}
888
889impl Default for ExecuteRequest {
890 fn default() -> Self {
891 Self {
892 code: "".to_string(),
893 silent: false,
894 store_history: true,
895 user_expressions: None,
896 allow_stdin: false,
897 stop_on_error: true,
898 }
899 }
900}
901
902#[derive(Serialize, Deserialize, Debug, Clone)]
910pub struct ExecuteReply {
911 #[serde(default)]
912 pub status: ReplyStatus,
913 pub execution_count: ExecutionCount,
914
915 #[serde(default)]
916 pub payload: Vec<Payload>,
917 pub user_expressions: Option<HashMap<String, String>>,
918
919 #[serde(flatten, skip_serializing_if = "Option::is_none")]
920 pub error: Option<Box<ReplyError>>,
921}
922impl Default for ExecuteReply {
923 fn default() -> Self {
924 Self {
925 status: ReplyStatus::Ok,
926 execution_count: ExecutionCount::new(0),
927 payload: Vec::new(),
928 user_expressions: None,
929 error: None,
930 }
931 }
932}
933
934#[derive(Serialize, Deserialize, Debug, Clone)]
939#[serde(rename_all = "snake_case")]
940#[serde(tag = "source")]
941pub enum Payload {
942 Page {
943 data: Media,
944 start: usize,
945 },
946 SetNextInput {
947 text: String,
948 replace: bool,
949 },
950 EditMagic {
951 filename: String,
952 line_number: usize,
953 },
954 AskExit {
955 keepkernel: bool,
957 },
958}
959
960#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
964pub struct KernelInfoRequest {}
965
966#[derive(Serialize, Deserialize, Debug, Clone)]
970pub struct KernelInfoReply {
971 pub status: ReplyStatus,
972 pub protocol_version: String,
973 pub implementation: String,
974 pub implementation_version: String,
975 pub language_info: LanguageInfo,
976 pub banner: String,
977 pub help_links: Vec<HelpLink>,
978 #[serde(default = "default_debugger")]
979 pub debugger: bool,
980 #[serde(flatten, skip_serializing_if = "Option::is_none")]
981 pub error: Option<Box<ReplyError>>,
982}
983
984fn default_debugger() -> bool {
985 false
986}
987
988#[derive(Serialize, Deserialize, Debug, Clone)]
989#[serde(untagged)]
990pub enum CodeMirrorMode {
991 Simple(String),
992 CustomMode { name: String, version: usize },
993}
994
995#[derive(Serialize, Deserialize, Debug, Clone)]
996pub struct CodeMirrorModeObject {
997 pub name: String,
998 pub version: usize,
999}
1000
1001impl CodeMirrorMode {
1002 pub fn typescript() -> Self {
1003 Self::Simple("typescript".to_string())
1004 }
1005
1006 pub fn python() -> Self {
1007 Self::Simple("python".to_string())
1008 }
1009
1010 pub fn ipython_code_mirror_mode() -> Self {
1011 Self::CustomMode {
1012 name: "ipython".to_string(),
1013 version: 3,
1014 }
1015 }
1016}
1017
1018#[derive(Serialize, Deserialize, Debug, Clone)]
1019pub struct LanguageInfo {
1020 pub name: String,
1021 pub version: String,
1022 #[serde(skip_serializing_if = "Option::is_none")]
1023 pub mimetype: Option<String>,
1024 #[serde(skip_serializing_if = "Option::is_none")]
1025 pub file_extension: Option<String>,
1026 #[serde(skip_serializing_if = "Option::is_none")]
1027 pub pygments_lexer: Option<String>,
1028 #[serde(skip_serializing_if = "Option::is_none")]
1029 pub codemirror_mode: Option<CodeMirrorMode>,
1030 #[serde(skip_serializing_if = "Option::is_none")]
1031 pub nbconvert_exporter: Option<String>,
1032}
1033
1034#[derive(Serialize, Deserialize, Debug, Clone)]
1035pub struct HelpLink {
1036 pub text: String,
1037 pub url: String,
1038}
1039
1040#[derive(Serialize, Deserialize, Debug, Clone)]
1041pub enum Stdio {
1042 #[serde(rename = "stdout")]
1043 Stdout,
1044 #[serde(rename = "stderr")]
1045 Stderr,
1046}
1047
1048#[derive(Serialize, Deserialize, Debug, Clone)]
1090pub struct StreamContent {
1091 pub name: Stdio,
1092 pub text: String,
1093}
1094impl Default for StreamContent {
1095 fn default() -> Self {
1096 Self {
1097 name: Stdio::Stdout,
1098 text: String::new(),
1099 }
1100 }
1101}
1102
1103impl StreamContent {
1104 pub fn stdout(text: &str) -> Self {
1105 Self {
1106 name: Stdio::Stdout,
1107 text: text.to_string(),
1108 }
1109 }
1110
1111 pub fn stderr(text: &str) -> Self {
1112 Self {
1113 name: Stdio::Stderr,
1114 text: text.to_string(),
1115 }
1116 }
1117}
1118
1119#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1121pub struct Transient {
1122 #[serde(skip_serializing_if = "Option::is_none")]
1123 pub display_id: Option<String>,
1124}
1125
1126#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1166pub struct DisplayData {
1167 pub data: Media,
1168 pub metadata: serde_json::Map<String, Value>,
1169 #[serde(default, skip_serializing_if = "Option::is_none")]
1170 pub transient: Option<Transient>,
1171}
1172
1173impl DisplayData {
1174 pub fn new(data: Media) -> Self {
1175 Self {
1176 data,
1177 metadata: Default::default(),
1178 transient: Default::default(),
1179 }
1180 }
1181}
1182
1183impl From<Vec<MediaType>> for DisplayData {
1184 fn from(content: Vec<MediaType>) -> Self {
1185 Self::new(Media::new(content))
1186 }
1187}
1188
1189impl From<MediaType> for DisplayData {
1190 fn from(content: MediaType) -> Self {
1191 Self::new(Media::new(vec![content]))
1192 }
1193}
1194
1195#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1198pub struct UpdateDisplayData {
1199 pub data: Media,
1200 #[serde(default)]
1201 pub metadata: serde_json::Map<String, Value>,
1202 pub transient: Transient,
1203}
1204
1205impl UpdateDisplayData {
1206 pub fn new(data: Media, display_id: &str) -> Self {
1207 Self {
1208 data,
1209 metadata: Default::default(),
1210 transient: Transient {
1211 display_id: Some(display_id.to_string()),
1212 },
1213 }
1214 }
1215}
1216
1217#[derive(Serialize, Deserialize, Debug, Clone)]
1223pub struct ExecuteInput {
1224 pub code: String,
1225 pub execution_count: ExecutionCount,
1226}
1227impl Default for ExecuteInput {
1228 fn default() -> Self {
1229 Self {
1230 code: String::new(),
1231 execution_count: ExecutionCount::new(0),
1232 }
1233 }
1234}
1235
1236#[derive(Serialize, Deserialize, Debug, Clone)]
1260pub struct ExecuteResult {
1261 pub execution_count: ExecutionCount,
1262 pub data: Media,
1263 #[serde(default)]
1264 pub metadata: serde_json::Map<String, Value>,
1265 pub transient: Option<Transient>,
1266}
1267impl Default for ExecuteResult {
1268 fn default() -> Self {
1269 Self {
1270 execution_count: ExecutionCount::new(0),
1271 data: Media::default(),
1272 metadata: serde_json::Map::new(),
1273 transient: None,
1274 }
1275 }
1276}
1277
1278impl ExecuteResult {
1279 pub fn new(execution_count: ExecutionCount, data: Media) -> Self {
1280 Self {
1281 execution_count,
1282 data,
1283 metadata: Default::default(),
1284 transient: None,
1285 }
1286 }
1287}
1288
1289impl From<(ExecutionCount, Vec<MediaType>)> for ExecuteResult {
1290 fn from((execution_count, content): (ExecutionCount, Vec<MediaType>)) -> Self {
1291 Self::new(execution_count, content.into())
1292 }
1293}
1294
1295impl From<(ExecutionCount, MediaType)> for ExecuteResult {
1296 fn from((execution_count, content): (ExecutionCount, MediaType)) -> Self {
1297 Self::new(execution_count, content.into())
1298 }
1299}
1300
1301#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1307pub struct ErrorOutput {
1308 pub ename: String,
1309 pub evalue: String,
1310 pub traceback: Vec<String>,
1311}
1312
1313#[derive(Serialize, Deserialize, Debug, Clone)]
1341pub struct CommOpen {
1342 pub comm_id: CommId,
1343 pub target_name: String,
1344 pub data: serde_json::Map<String, Value>,
1345 #[serde(skip_serializing_if = "Option::is_none")]
1346 pub target_module: Option<String>,
1347}
1348impl Default for CommOpen {
1349 fn default() -> Self {
1350 Self {
1351 comm_id: CommId("".to_string()),
1352 target_name: String::new(),
1353 data: serde_json::Map::new(),
1354 target_module: None,
1355 }
1356 }
1357}
1358
1359#[derive(Serialize, Deserialize, Debug, Clone)]
1378pub struct CommMsg {
1379 pub comm_id: CommId,
1380 pub data: serde_json::Map<String, Value>,
1381}
1382impl Default for CommMsg {
1383 fn default() -> Self {
1384 Self {
1385 comm_id: CommId("".to_string()),
1386 data: serde_json::Map::new(),
1387 }
1388 }
1389}
1390
1391#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1392pub struct CommInfoRequest {
1393 pub target_name: Option<String>,
1394}
1395
1396#[derive(Eq, Hash, PartialEq, Serialize, Deserialize, Debug, Clone)]
1397pub struct CommId(pub String);
1398
1399impl From<CommId> for String {
1400 fn from(comm_id: CommId) -> Self {
1401 comm_id.0
1402 }
1403}
1404
1405impl From<String> for CommId {
1406 fn from(comm_id: String) -> Self {
1407 Self(comm_id)
1408 }
1409}
1410
1411#[derive(Serialize, Deserialize, Debug, Clone)]
1412pub struct CommInfo {
1413 pub target_name: String,
1414}
1415
1416#[derive(Serialize, Deserialize, Debug, Clone)]
1417pub struct CommInfoReply {
1418 #[serde(default)]
1419 pub status: ReplyStatus,
1420 pub comms: HashMap<CommId, CommInfo>,
1421 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1423 pub error: Option<Box<ReplyError>>,
1424}
1425impl Default for CommInfoReply {
1426 fn default() -> Self {
1427 Self {
1428 status: ReplyStatus::Ok,
1429 comms: HashMap::new(),
1430 error: None,
1431 }
1432 }
1433}
1434
1435#[derive(Serialize, Deserialize, Debug, Clone)]
1440pub struct CommClose {
1441 pub comm_id: CommId,
1442 pub data: serde_json::Map<String, Value>,
1443}
1444impl Default for CommClose {
1445 fn default() -> Self {
1446 Self {
1447 comm_id: CommId("".to_string()),
1448 data: serde_json::Map::new(),
1449 }
1450 }
1451}
1452
1453#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1454pub struct ShutdownRequest {
1461 pub restart: bool,
1462}
1463
1464#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1465pub struct InterruptRequest {}
1473
1474#[derive(Serialize, Deserialize, Debug, Clone)]
1475pub struct InterruptReply {
1482 pub status: ReplyStatus,
1483
1484 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1485 pub error: Option<Box<ReplyError>>,
1486}
1487
1488impl Default for InterruptReply {
1489 fn default() -> Self {
1490 Self::new()
1491 }
1492}
1493
1494impl InterruptReply {
1495 pub fn new() -> Self {
1496 Self {
1497 status: ReplyStatus::Ok,
1498 error: None,
1499 }
1500 }
1501}
1502
1503#[derive(Serialize, Deserialize, Debug, Clone)]
1504pub struct ShutdownReply {
1511 pub restart: bool,
1512 pub status: ReplyStatus,
1513
1514 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1515 pub error: Option<Box<ReplyError>>,
1516}
1517impl Default for ShutdownReply {
1518 fn default() -> Self {
1519 Self {
1520 restart: false,
1521 status: ReplyStatus::Ok,
1522 error: None,
1523 }
1524 }
1525}
1526
1527#[derive(Serialize, Deserialize, Debug, Clone)]
1528pub struct InputRequest {
1535 pub prompt: String,
1536 pub password: bool,
1537}
1538impl Default for InputRequest {
1539 fn default() -> Self {
1540 Self {
1541 prompt: "> ".to_string(),
1542 password: false,
1543 }
1544 }
1545}
1546
1547#[derive(Serialize, Deserialize, Debug, Clone)]
1548pub struct InputReply {
1555 pub value: String,
1556
1557 pub status: ReplyStatus,
1558 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1559 pub error: Option<Box<ReplyError>>,
1560}
1561impl Default for InputReply {
1562 fn default() -> Self {
1563 Self {
1564 value: String::new(),
1565 status: ReplyStatus::Ok,
1566 error: None,
1567 }
1568 }
1569}
1570
1571#[derive(Serialize, Deserialize, Debug, Clone)]
1577pub struct InspectRequest {
1578 pub code: String,
1581 pub cursor_pos: usize,
1583 pub detail_level: Option<usize>,
1588}
1589impl Default for InspectRequest {
1590 fn default() -> Self {
1591 Self {
1592 code: String::new(),
1593 cursor_pos: 0,
1594 detail_level: Some(0),
1595 }
1596 }
1597}
1598
1599#[derive(Serialize, Deserialize, Debug, Clone)]
1600pub struct InspectReply {
1601 pub found: bool,
1602 pub data: Media,
1603 pub metadata: serde_json::Map<String, Value>,
1604 #[serde(default)]
1605 pub status: ReplyStatus,
1606 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1607 pub error: Option<Box<ReplyError>>,
1608}
1609impl Default for InspectReply {
1610 fn default() -> Self {
1611 Self {
1612 found: false,
1613 data: Media::default(),
1614 metadata: serde_json::Map::new(),
1615 status: ReplyStatus::Ok,
1616 error: None,
1617 }
1618 }
1619}
1620
1621#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1625pub struct CompleteRequest {
1626 pub code: String,
1627 pub cursor_pos: usize,
1628}
1629
1630#[derive(Serialize, Deserialize, Debug, Clone)]
1634pub struct CompleteReply {
1635 pub matches: Vec<String>,
1636 pub cursor_start: usize,
1637 pub cursor_end: usize,
1638 pub metadata: serde_json::Map<String, Value>,
1639 #[serde(default)]
1640 pub status: ReplyStatus,
1641 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1642 pub error: Option<Box<ReplyError>>,
1643}
1644impl Default for CompleteReply {
1645 fn default() -> Self {
1646 Self {
1647 matches: Vec::new(),
1648 cursor_start: 0,
1649 cursor_end: 0,
1650 metadata: serde_json::Map::new(),
1651 status: ReplyStatus::Ok,
1652 error: None,
1653 }
1654 }
1655}
1656
1657#[derive(Serialize, Deserialize, Debug, Clone)]
1658pub struct DebugRequest {
1659 #[serde(flatten)]
1660 pub content: Value,
1661}
1662impl Default for DebugRequest {
1663 fn default() -> Self {
1664 Self {
1665 content: Value::Null,
1666 }
1667 }
1668}
1669
1670#[derive(Serialize, Deserialize, Debug, Clone)]
1671pub struct DebugReply {
1672 #[serde(flatten)]
1673 pub content: Value,
1674}
1675impl Default for DebugReply {
1676 fn default() -> Self {
1677 Self {
1678 content: Value::Null,
1679 }
1680 }
1681}
1682
1683#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
1684#[serde(rename_all = "snake_case")]
1685pub enum IsCompleteReplyStatus {
1686 Incomplete,
1689 Complete,
1691 Invalid,
1693 Unknown,
1698}
1699
1700#[derive(Serialize, Deserialize, Debug, Clone)]
1701pub struct IsCompleteReply {
1702 pub status: IsCompleteReplyStatus,
1705 pub indent: String,
1710}
1711impl Default for IsCompleteReply {
1712 fn default() -> Self {
1713 Self {
1714 status: IsCompleteReplyStatus::Unknown,
1715 indent: String::new(),
1716 }
1717 }
1718}
1719
1720impl IsCompleteReply {
1721 pub fn new(status: IsCompleteReplyStatus, indent: String) -> Self {
1722 Self { status, indent }
1723 }
1724
1725 pub fn incomplete(indent: String) -> Self {
1726 Self::new(IsCompleteReplyStatus::Incomplete, indent)
1727 }
1728
1729 pub fn complete() -> Self {
1730 Self::new(IsCompleteReplyStatus::Complete, String::new())
1731 }
1732
1733 pub fn invalid() -> Self {
1734 Self::new(IsCompleteReplyStatus::Invalid, String::new())
1735 }
1736
1737 pub fn unknown() -> Self {
1738 Self::new(IsCompleteReplyStatus::Unknown, String::new())
1739 }
1740}
1741
1742#[derive(Serialize, Deserialize, Debug, Clone)]
1743#[serde(tag = "hist_access_type")]
1744pub enum HistoryRequest {
1745 #[serde(rename = "range")]
1746 Range {
1747 session: Option<i32>,
1748 start: i32,
1749 stop: i32,
1750 output: bool,
1751 raw: bool,
1752 },
1753 #[serde(rename = "tail")]
1754 Tail { n: i32, output: bool, raw: bool },
1755 #[serde(rename = "search")]
1756 Search {
1757 pattern: String,
1758 unique: bool,
1759 output: bool,
1760 raw: bool,
1761 n: i32,
1762 },
1763}
1764impl Default for HistoryRequest {
1765 fn default() -> Self {
1766 Self::Range {
1767 session: None,
1768 start: 0,
1769 stop: 0,
1770 output: false,
1771 raw: false,
1772 }
1773 }
1774}
1775
1776#[derive(Serialize, Deserialize, Debug, Clone)]
1777#[serde(untagged)]
1778pub enum HistoryEntry {
1779 Input(usize, usize, String),
1782 InputOutput(usize, usize, (String, String)),
1785}
1786
1787#[derive(Serialize, Deserialize, Debug, Clone)]
1791pub struct HistoryReply {
1792 pub history: Vec<HistoryEntry>,
1793
1794 pub status: ReplyStatus,
1795 #[serde(flatten, skip_serializing_if = "Option::is_none")]
1796 pub error: Option<Box<ReplyError>>,
1797}
1798impl Default for HistoryReply {
1799 fn default() -> Self {
1800 Self {
1801 history: Vec::new(),
1802 status: ReplyStatus::Ok,
1803 error: None,
1804 }
1805 }
1806}
1807
1808impl HistoryReply {
1809 pub fn new(history: Vec<HistoryEntry>) -> Self {
1810 Self {
1811 history,
1812 status: ReplyStatus::Ok,
1813 error: None,
1814 }
1815 }
1816}
1817
1818#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1822pub struct IsCompleteRequest {
1823 pub code: String,
1824}
1825
1826#[derive(Debug, Clone, PartialEq)]
1827pub enum ExecutionState {
1828 Unknown,
1829 Starting,
1830 Busy,
1831 Idle,
1832 Restarting,
1833 Terminating,
1834 AutoRestarting,
1835 Dead,
1836 Other(String),
1837}
1838
1839impl ExecutionState {
1840 pub fn as_str(&self) -> &str {
1841 match self {
1842 ExecutionState::Unknown => "unknown",
1843 ExecutionState::Terminating => "terminating",
1844 ExecutionState::AutoRestarting => "autorestarting",
1845 ExecutionState::Dead => "dead",
1846 ExecutionState::Busy => "busy",
1847 ExecutionState::Idle => "idle",
1848 ExecutionState::Starting => "starting",
1849 ExecutionState::Restarting => "restarting",
1850 ExecutionState::Other(s) => s,
1851 }
1852 }
1853}
1854
1855impl serde::Serialize for ExecutionState {
1856 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1857 where
1858 S: serde::Serializer,
1859 {
1860 match self {
1861 ExecutionState::Unknown => serializer.serialize_str("unknown"),
1862 ExecutionState::Terminating => serializer.serialize_str("terminating"),
1863 ExecutionState::AutoRestarting => serializer.serialize_str("autorestarting"),
1864 ExecutionState::Dead => serializer.serialize_str("dead"),
1865 ExecutionState::Busy => serializer.serialize_str("busy"),
1866 ExecutionState::Idle => serializer.serialize_str("idle"),
1867 ExecutionState::Starting => serializer.serialize_str("starting"),
1868 ExecutionState::Restarting => serializer.serialize_str("restarting"),
1869 ExecutionState::Other(s) => serializer.serialize_str(s),
1870 }
1871 }
1872}
1873
1874impl<'de> serde::Deserialize<'de> for ExecutionState {
1875 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1876 where
1877 D: serde::Deserializer<'de>,
1878 {
1879 struct ExecutionStateVisitor;
1880
1881 impl serde::de::Visitor<'_> for ExecutionStateVisitor {
1882 type Value = ExecutionState;
1883
1884 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1885 formatter.write_str("a string representing an execution state")
1886 }
1887 fn visit_str<E>(self, value: &str) -> Result<ExecutionState, E>
1888 where
1889 E: serde::de::Error,
1890 {
1891 match value {
1892 "unknown" => Ok(ExecutionState::Unknown),
1893 "terminating" => Ok(ExecutionState::Terminating),
1894 "autorestarting" => Ok(ExecutionState::AutoRestarting),
1895 "dead" => Ok(ExecutionState::Dead),
1896 "busy" => Ok(ExecutionState::Busy),
1897 "idle" => Ok(ExecutionState::Idle),
1898 "starting" => Ok(ExecutionState::Starting),
1899 "restarting" => Ok(ExecutionState::Restarting),
1900 other => Ok(ExecutionState::Other(other.to_string())),
1901 }
1902 }
1903 }
1904 deserializer.deserialize_str(ExecutionStateVisitor)
1905 }
1906}
1907
1908#[derive(Serialize, Deserialize, Debug, Clone)]
1912pub struct Status {
1913 pub execution_state: ExecutionState,
1914}
1915impl Default for Status {
1916 fn default() -> Self {
1917 Self {
1918 execution_state: ExecutionState::Idle,
1919 }
1920 }
1921}
1922
1923impl Status {
1924 pub fn busy() -> Self {
1925 Self {
1926 execution_state: ExecutionState::Busy,
1927 }
1928 }
1929
1930 pub fn idle() -> Self {
1931 Self {
1932 execution_state: ExecutionState::Idle,
1933 }
1934 }
1935
1936 pub fn starting() -> Self {
1937 Self {
1938 execution_state: ExecutionState::Starting,
1939 }
1940 }
1941
1942 pub fn restarting() -> Self {
1943 Self {
1944 execution_state: ExecutionState::Restarting,
1945 }
1946 }
1947
1948 pub fn other(state: impl Into<String>) -> Self {
1949 Self {
1950 execution_state: ExecutionState::Other(state.into()),
1951 }
1952 }
1953}
1954
1955#[cfg(test)]
1956mod test {
1957 use serde_json::json;
1958
1959 use super::*;
1960
1961 #[test]
1962 fn test_execute_request_serialize() {
1963 let request = ExecuteRequest {
1964 code: "print('Hello, World!')".to_string(),
1965 silent: false,
1966 store_history: true,
1967 user_expressions: Some(HashMap::new()),
1968 allow_stdin: false,
1969 stop_on_error: true,
1970 };
1971 let request_value = serde_json::to_value(request).unwrap();
1972
1973 let expected_request_value = serde_json::json!({
1974 "code": "print('Hello, World!')",
1975 "silent": false,
1976 "store_history": true,
1977 "user_expressions": {},
1978 "allow_stdin": false,
1979 "stop_on_error": true
1980 });
1981
1982 assert_eq!(request_value, expected_request_value);
1983 }
1984
1985 #[test]
1986 fn test_execute_request_user_expressions_serializes_to_empty_dict() {
1987 let request = ExecuteRequest {
1988 code: "print('Hello, World!')".to_string(),
1989 silent: false,
1990 store_history: true,
1991 user_expressions: None,
1992 allow_stdin: false,
1993 stop_on_error: true,
1994 };
1995 let request_value = serde_json::to_value(request).unwrap();
1996
1997 let expected_request_value = serde_json::json!({
1998 "code": "print('Hello, World!')",
1999 "silent": false,
2000 "store_history": true,
2001 "user_expressions": {},
2002 "allow_stdin": false,
2003 "stop_on_error": true
2004 });
2005
2006 assert_eq!(request_value, expected_request_value);
2007 }
2008
2009 #[test]
2010 fn test_into_various() {
2011 let kernel_info_request = KernelInfoRequest {};
2012 let content: JupyterMessageContent = kernel_info_request.clone().into();
2013 let message: JupyterMessage = content.into();
2014 assert!(message.parent_header.is_none());
2015 match message.content {
2016 JupyterMessageContent::KernelInfoRequest(req) => {
2017 assert_eq!(req, kernel_info_request);
2018 }
2019 _ => panic!("Expected KernelInfoRequest"),
2020 }
2021
2022 let kernel_info_request = KernelInfoRequest {};
2023 let message: JupyterMessage = kernel_info_request.clone().into();
2024 assert!(message.parent_header.is_none());
2025 match message.content {
2026 JupyterMessageContent::KernelInfoRequest(req) => {
2027 assert_eq!(req, kernel_info_request);
2028 }
2029 _ => panic!("Expected KernelInfoRequest"),
2030 }
2031 }
2032
2033 #[test]
2034 fn test_default() {
2035 let msg: JupyterMessage = ExecuteRequest {
2036 code: "import this".to_string(),
2037 ..Default::default()
2038 }
2039 .into();
2040
2041 assert_eq!(msg.header.msg_type, "execute_request");
2042 assert_eq!(msg.header.msg_id.len(), 36);
2043
2044 match msg.content {
2045 JupyterMessageContent::ExecuteRequest(req) => {
2046 assert_eq!(req.code, "import this");
2047 assert!(!req.silent);
2048 assert!(req.store_history);
2049 assert_eq!(req.user_expressions, None);
2050 assert!(!req.allow_stdin);
2051 assert!(req.stop_on_error);
2052 }
2053 _ => panic!("Expected ExecuteRequest"),
2054 }
2055 }
2056
2057 #[test]
2058 fn test_deserialize_payload() {
2059 let raw_execute_reply_content = r#"
2060 {
2061 "status": "ok",
2062 "execution_count": 1,
2063 "payload": [{
2064 "source": "page",
2065 "data": {
2066 "text/html": "<h1>Hello</h1>",
2067 "text/plain": "Hello"
2068 },
2069 "start": 0
2070 }],
2071 "user_expressions": {}
2072 }
2073 "#;
2074
2075 let execute_reply: ExecuteReply = serde_json::from_str(raw_execute_reply_content).unwrap();
2076
2077 assert_eq!(execute_reply.status, ReplyStatus::Ok);
2078 assert_eq!(execute_reply.execution_count, ExecutionCount::new(1));
2079
2080 let payload = execute_reply.payload.clone();
2081
2082 assert_eq!(payload.len(), 1);
2083 let payload = payload.first().unwrap();
2084
2085 let media = match payload {
2086 Payload::Page { data, .. } => data,
2087 _ => panic!("Expected Page payload type"),
2088 };
2089
2090 let media = serde_json::to_value(media).unwrap();
2091
2092 let expected_media = serde_json::json!({
2093 "text/html": "<h1>Hello</h1>",
2094 "text/plain": "Hello"
2095 });
2096
2097 assert_eq!(media, expected_media);
2098 }
2099
2100 #[test]
2101 pub fn test_display_data_various_data() {
2102 let display_data = DisplayData {
2103 data: serde_json::from_value(json!({
2104 "text/plain": "Hello, World!",
2105 "text/html": "<h1>Hello, World!</h1>",
2106 "application/json": {
2107 "hello": "world",
2108 "foo": "bar",
2109 "ok": [1, 2, 3],
2110 }
2111 }))
2112 .unwrap(),
2113 ..Default::default()
2114 };
2115
2116 let display_data_value = serde_json::to_value(display_data).unwrap();
2117
2118 let expected_display_data_value = serde_json::json!({
2119 "data": {
2120 "text/plain": "Hello, World!",
2121 "text/html": "<h1>Hello, World!</h1>",
2122 "application/json": {
2123 "hello": "world",
2124 "foo": "bar",
2125 "ok": [1, 2, 3]
2126 }
2127 },
2128 "metadata": {}
2129 });
2130
2131 assert_eq!(display_data_value, expected_display_data_value);
2132 }
2133
2134 use std::mem::size_of;
2135
2136 macro_rules! size_of_variant {
2137 ($variant:ty) => {
2138 let size = size_of::<$variant>();
2139 println!("The size of {} is: {} bytes", stringify!($variant), size);
2140
2141 assert!(size <= 96);
2142 };
2143 }
2144
2145 #[test]
2146 fn test_enum_variant_sizes() {
2147 size_of_variant!(ClearOutput);
2148 size_of_variant!(CommClose);
2149 size_of_variant!(CommInfoReply);
2150 size_of_variant!(CommInfoRequest);
2151 size_of_variant!(CommMsg);
2152 size_of_variant!(CommOpen);
2153 size_of_variant!(CompleteReply);
2154 size_of_variant!(CompleteRequest);
2155 size_of_variant!(DebugReply);
2156 size_of_variant!(DebugRequest);
2157 size_of_variant!(DisplayData);
2158 size_of_variant!(ErrorOutput);
2159 size_of_variant!(ExecuteInput);
2160 size_of_variant!(ExecuteReply);
2161 size_of_variant!(ExecuteRequest);
2162 size_of_variant!(ExecuteResult);
2163 size_of_variant!(HistoryReply);
2164 size_of_variant!(HistoryRequest);
2165 size_of_variant!(InputReply);
2166 size_of_variant!(InputRequest);
2167 size_of_variant!(InspectReply);
2168 size_of_variant!(InspectRequest);
2169 size_of_variant!(InterruptReply);
2170 size_of_variant!(InterruptRequest);
2171 size_of_variant!(IsCompleteReply);
2172 size_of_variant!(IsCompleteRequest);
2173 size_of_variant!(Box<KernelInfoReply>);
2174 size_of_variant!(KernelInfoRequest);
2175 size_of_variant!(ShutdownReply);
2176 size_of_variant!(ShutdownRequest);
2177 size_of_variant!(Status);
2178 size_of_variant!(StreamContent);
2179 size_of_variant!(UnknownMessage);
2180 size_of_variant!(UpdateDisplayData);
2181 }
2182
2183 #[test]
2184 fn test_jupyter_message_content_enum_size() {
2185 let size = size_of::<JupyterMessageContent>();
2186 println!("The size of JupyterMessageContent is: {}", size);
2187 assert!(size > 0);
2188 assert!(size <= 104);
2189 }
2190
2191 #[test]
2192 fn test_jupyter_message_parent_header_serializes_to_empty_dict() {
2193 let request = ExecuteRequest {
2194 code: "1 + 1".to_string(),
2195 ..Default::default()
2196 };
2197 let message = JupyterMessage::from(request);
2198
2199 let serialized_message = serde_json::to_value(message).unwrap();
2200
2201 let parent_header = serialized_message.get("parent_header").unwrap();
2203 assert!(parent_header.is_object());
2204 assert!(parent_header.as_object().unwrap().is_empty());
2205 }
2206
2207 #[test]
2208 fn test_user_expressions_serialization() {
2209 let request = ExecuteRequest {
2210 code: "pass".to_string(),
2211 silent: false,
2212 store_history: true,
2213 user_expressions: Some(HashMap::from([(
2214 String::from("expression"),
2215 String::from("42 + 7"),
2216 )])),
2217 allow_stdin: false,
2218 stop_on_error: true,
2219 };
2220 let request_value = serde_json::to_value(request.clone()).unwrap();
2221
2222 let expected_request_value = serde_json::json!({
2223 "code": "pass",
2224 "silent": false,
2225 "store_history": true,
2226 "user_expressions": {"expression": "42 + 7"},
2227 "allow_stdin": false,
2228 "stop_on_error": true
2229 });
2230
2231 assert_eq!(request_value, expected_request_value);
2232
2233 let deserialized_request: ExecuteRequest = serde_json::from_value(request_value).unwrap();
2234 assert_eq!(
2235 deserialized_request.user_expressions,
2236 request.user_expressions
2237 );
2238 }
2239
2240 #[test]
2241 fn test_jupyter_message_parent_header_deserialize() {
2242 let msg = r#"
2243 {
2244 "buffers": [],
2245 "channel": "shell",
2246 "content": {},
2247 "header": {
2248 "date": "2025-05-14T14:32:23.490Z",
2249 "msg_id": "44bd6b44-78a1-4892-87df-c0861a005d56",
2250 "msg_type": "kernel_info_request",
2251 "session": "b75bddaa-6d69-4340-ba13-81516192370e",
2252 "username": "",
2253 "version": "5.2"
2254 },
2255 "metadata": {},
2256 "parent_header": {
2257 "date": "2025-05-14T14:32:23.490Z",
2258 "msg_id": "2aaf8916-6b83-4f5a-80dd-633e94f5d8e1",
2259 "msg_type": "kernel_info_request",
2260 "session": "e2a3165d-76a8-4fef-850f-712102589660",
2261 "username": "",
2262 "version": "5.2"
2263 }
2264}
2265 "#;
2266
2267 let message: JupyterMessage = serde_json::from_str(msg).unwrap();
2268 assert!(message.parent_header.is_some());
2269 assert_eq!(
2270 message.parent_header.as_ref().unwrap().msg_type,
2271 "kernel_info_request"
2272 );
2273 assert_eq!(
2274 message.parent_header.as_ref().unwrap().msg_id,
2275 "2aaf8916-6b83-4f5a-80dd-633e94f5d8e1"
2276 );
2277 assert_eq!(
2278 message.header.msg_id,
2279 "44bd6b44-78a1-4892-87df-c0861a005d56"
2280 );
2281 }
2282
2283 #[test]
2284 fn test_jupyter_message_empty_parent_header_deserialize() {
2285 let msg = r#"
2286 {
2287 "buffers": [],
2288 "channel": "shell",
2289 "content": {},
2290 "header": {
2291 "date": "2025-05-14T14:32:23.490Z",
2292 "msg_id": "44bd6b44-78a1-4892-87df-c0861a005d56",
2293 "msg_type": "kernel_info_request",
2294 "session": "b75bddaa-6d69-4340-ba13-81516192370e",
2295 "username": "",
2296 "version": "5.2"
2297 },
2298 "metadata": {},
2299 "parent_header": {}
2300}
2301 "#;
2302
2303 let message: JupyterMessage = serde_json::from_str(msg).unwrap();
2304 assert!(message.parent_header.is_none());
2305 assert_eq!(message.header.msg_type, "kernel_info_request");
2306 assert_eq!(
2307 message.header.msg_id,
2308 "44bd6b44-78a1-4892-87df-c0861a005d56"
2309 );
2310 }
2311
2312 #[test]
2313 fn test_execution_state_other_serde() {
2314 let json = r#""busy""#;
2315 let state: ExecutionState = serde_json::from_str(json).unwrap();
2316 assert_eq!(state, ExecutionState::Busy);
2317 let serialized = serde_json::to_string(&state).unwrap();
2318 assert_eq!(serialized, "\"busy\"");
2319
2320 let state = ExecutionState::Idle;
2321 let serialized = serde_json::to_string(&state).unwrap();
2322 assert_eq!(serialized, "\"idle\"");
2323 let state: ExecutionState = serde_json::from_str(&serialized).unwrap();
2324 assert_eq!(state, ExecutionState::Idle);
2325
2326 let json = r#""disconnected""#;
2327 let state: ExecutionState = serde_json::from_str(json).unwrap();
2328 assert_eq!(state, ExecutionState::Other("disconnected".to_string()));
2329 let serialized = serde_json::to_string(&state).unwrap();
2330 assert_eq!(serialized, "\"disconnected\"");
2331 }
2332}