1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use std::time::Duration;
4
5use crate::timing::ExecutionTiming;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9#[serde(tag = "cell_type")]
10pub enum Cell {
11 #[serde(rename = "code")]
13 Code(CodeCell),
14 #[serde(rename = "markdown")]
16 Markdown(MarkdownCell),
17 #[serde(rename = "raw")]
19 Raw(RawCell),
20}
21
22impl Cell {
23 pub fn source(&self) -> &Source {
25 match self {
26 Cell::Code(c) => &c.source,
27 Cell::Markdown(m) => &m.source,
28 Cell::Raw(r) => &r.source,
29 }
30 }
31
32 pub fn source_mut(&mut self) -> &mut Source {
34 match self {
35 Cell::Code(c) => &mut c.source,
36 Cell::Markdown(m) => &mut m.source,
37 Cell::Raw(r) => &mut r.source,
38 }
39 }
40
41 pub fn metadata(&self) -> &CellMetadata {
43 match self {
44 Cell::Code(c) => &c.metadata,
45 Cell::Markdown(m) => &m.metadata,
46 Cell::Raw(r) => &r.metadata,
47 }
48 }
49
50 pub fn is_code(&self) -> bool {
52 matches!(self, Cell::Code(_))
53 }
54
55 pub fn cell_type(&self) -> &str {
57 match self {
58 Cell::Code(_) => "code",
59 Cell::Markdown(_) => "markdown",
60 Cell::Raw(_) => "raw",
61 }
62 }
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct CodeCell {
68 pub source: Source,
70 #[serde(default)]
72 pub metadata: CellMetadata,
73 pub execution_count: Option<i32>,
75 #[serde(default)]
77 pub outputs: Vec<Output>,
78}
79
80impl CodeCell {
81 pub fn timing(&self) -> Option<ExecutionTiming> {
86 self.metadata
87 .extra
88 .get("execution")
89 .and_then(|v| serde_json::from_value(v.clone()).ok())
90 }
91
92 pub fn duration(&self) -> Option<Duration> {
96 self.timing()?.total_duration()
97 }
98
99 pub fn has_timing(&self) -> bool {
101 self.timing().map(|t| t.has_timing()).unwrap_or(false)
102 }
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct MarkdownCell {
108 pub source: Source,
110 #[serde(default)]
112 pub metadata: CellMetadata,
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct RawCell {
118 pub source: Source,
120 #[serde(default)]
122 pub metadata: CellMetadata,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127#[serde(untagged)]
128pub enum Source {
129 String(String),
131 Lines(Vec<String>),
133}
134
135impl Source {
136 pub fn as_str(&self) -> String {
138 match self {
139 Source::String(s) => s.clone(),
140 Source::Lines(lines) => lines.join(""),
141 }
142 }
143
144 pub fn as_lines(&self) -> Vec<String> {
146 match self {
147 Source::String(s) => s.lines().map(|l| l.to_string()).collect(),
148 Source::Lines(lines) => lines.clone(),
149 }
150 }
151}
152
153#[derive(Debug, Clone, Default, Serialize, Deserialize)]
155pub struct CellMetadata {
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub collapsed: Option<bool>,
159 #[serde(default, skip_serializing_if = "Vec::is_empty")]
161 pub tags: Vec<String>,
162 #[serde(flatten)]
164 pub extra: HashMap<String, serde_json::Value>,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize)]
169#[serde(tag = "output_type")]
170pub enum Output {
171 #[serde(rename = "stream")]
173 Stream {
174 name: String,
176 text: Source,
178 },
179
180 #[serde(rename = "display_data")]
182 DisplayData {
183 data: HashMap<String, serde_json::Value>,
185 #[serde(default)]
187 metadata: serde_json::Value,
188 },
189
190 #[serde(rename = "execute_result")]
192 ExecuteResult {
193 execution_count: i32,
195 data: HashMap<String, serde_json::Value>,
197 #[serde(default)]
199 metadata: serde_json::Value,
200 },
201
202 #[serde(rename = "error")]
204 Error {
205 ename: String,
207 evalue: String,
209 traceback: Vec<String>,
211 },
212}