1use rkyv::Archive;
2use serde::{Deserialize, Serialize};
3
4mod rkyv_json {
6 use rkyv::rancor::Fallible;
7 use rkyv::string::ArchivedString;
8 use rkyv::with::{ArchiveWith, DeserializeWith, SerializeWith};
9 use rkyv::{Archive, Place};
10
11 pub struct AsJsonString;
12
13 impl<T: serde::Serialize> ArchiveWith<T> for AsJsonString {
14 type Archived = ArchivedString;
15 type Resolver = <String as Archive>::Resolver;
16
17 fn resolve_with(field: &T, resolver: Self::Resolver, out: Place<Self::Archived>) {
18 let json = serde_json::to_string(field).expect("serde_json::to_string failed");
21 ArchivedString::resolve_from_str(&json, resolver, out);
22 }
23 }
24
25 impl<T: serde::Serialize, S: Fallible<Error: rkyv::rancor::Source> + rkyv::ser::Writer + ?Sized>
26 SerializeWith<T, S> for AsJsonString
27 {
28 fn serialize_with(field: &T, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
29 let json = serde_json::to_string(field).expect("serde_json::to_string failed");
31 ArchivedString::serialize_from_str(&json, serializer)
32 }
33 }
34
35 impl<T: serde::de::DeserializeOwned, D: Fallible + ?Sized> DeserializeWith<ArchivedString, T, D>
36 for AsJsonString
37 {
38 fn deserialize_with(archived: &ArchivedString, _: &mut D) -> Result<T, D::Error> {
39 Ok(serde_json::from_str(archived.as_str()).expect("serde_json::from_str failed"))
41 }
42 }
43}
44
45#[derive(
48 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
49)]
50pub struct Position {
51 pub start: Point,
52 pub end: Point,
53}
54
55#[derive(
56 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
57)]
58pub struct Point {
59 pub line: usize,
60 pub column: usize,
61 pub offset: usize,
62}
63
64#[derive(
66 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
67)]
68#[rkyv(serialize_bounds(
69 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
70))]
71#[rkyv(deserialize_bounds(
72 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
73))]
74#[rkyv(bytecheck(bounds(
75 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
76)))]
77pub struct Root {
78 #[serde(rename = "type")]
79 pub node_type: RootType,
80 #[rkyv(with = rkyv::with::Map<rkyv_json::AsJsonString>)]
81 pub frontmatter: Option<serde_json::Value>,
82 #[rkyv(omit_bounds)]
83 pub children: Vec<Node>,
84 pub position: Position,
85}
86
87#[derive(
88 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
89)]
90pub enum RootType {
91 #[serde(rename = "root")]
92 Root,
93}
94
95#[derive(
97 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
98)]
99#[rkyv(serialize_bounds(
100 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
101))]
102#[rkyv(deserialize_bounds(
103 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
104))]
105#[rkyv(bytecheck(bounds(
106 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
107)))]
108#[serde(tag = "type")]
109pub enum Node {
110 #[serde(rename = "text")]
111 Text(#[rkyv(omit_bounds)] TextNode),
112 #[serde(rename = "code_inline")]
113 CodeInline(#[rkyv(omit_bounds)] CodeInlineNode),
114 #[serde(rename = "code_block")]
115 CodeBlock(#[rkyv(omit_bounds)] CodeBlockNode),
116 #[serde(rename = "paragraph")]
117 Paragraph(#[rkyv(omit_bounds)] StandardBlockNode),
118 #[serde(rename = "heading")]
119 Heading(#[rkyv(omit_bounds)] StandardBlockNode),
120 #[serde(rename = "list")]
121 List(#[rkyv(omit_bounds)] StandardBlockNode),
122 #[serde(rename = "list_item")]
123 ListItem(#[rkyv(omit_bounds)] StandardBlockNode),
124 #[serde(rename = "blockquote")]
125 Blockquote(#[rkyv(omit_bounds)] StandardBlockNode),
126 #[serde(rename = "thematic_break")]
127 ThematicBreak(#[rkyv(omit_bounds)] StandardBlockNode),
128 #[serde(rename = "html")]
129 Html(#[rkyv(omit_bounds)] StandardBlockNode),
130 #[serde(rename = "table")]
131 Table(#[rkyv(omit_bounds)] StandardBlockNode),
132 #[serde(rename = "table_row")]
133 TableRow(#[rkyv(omit_bounds)] StandardBlockNode),
134 #[serde(rename = "table_cell")]
135 TableCell(#[rkyv(omit_bounds)] StandardBlockNode),
136 #[serde(rename = "link")]
137 Link(#[rkyv(omit_bounds)] LinkNode),
138 #[serde(rename = "image")]
139 Image(#[rkyv(omit_bounds)] ImageNode),
140 #[serde(rename = "emphasis")]
141 Emphasis(#[rkyv(omit_bounds)] StandardBlockNode),
142 #[serde(rename = "strong")]
143 Strong(#[rkyv(omit_bounds)] StandardBlockNode),
144 #[serde(rename = "strikethrough")]
145 Strikethrough(#[rkyv(omit_bounds)] StandardBlockNode),
146 #[serde(rename = "definition_list")]
147 DefinitionList(#[rkyv(omit_bounds)] StandardBlockNode),
148 #[serde(rename = "definition_term")]
149 DefinitionTerm(#[rkyv(omit_bounds)] StandardBlockNode),
150 #[serde(rename = "definition_description")]
151 DefinitionDescription(#[rkyv(omit_bounds)] StandardBlockNode),
152 #[serde(rename = "footnote_definition")]
153 FootnoteDefinition(#[rkyv(omit_bounds)] FootnoteNode),
154 #[serde(rename = "footnote_reference")]
155 FootnoteReference(#[rkyv(omit_bounds)] FootnoteNode),
156 #[serde(rename = "math_inline")]
157 MathInline(#[rkyv(omit_bounds)] MathNode),
158 #[serde(rename = "math_display")]
159 MathDisplay(#[rkyv(omit_bounds)] MathDisplayNode),
160 #[serde(rename = "citation")]
161 Citation(#[rkyv(omit_bounds)] CitationNode),
162 #[serde(rename = "cross_ref")]
163 CrossRef(#[rkyv(omit_bounds)] CrossRefNode),
164 #[serde(rename = "component")]
165 Component(#[rkyv(omit_bounds)] ComponentNode),
166 #[serde(rename = "variable")]
167 Variable(#[rkyv(omit_bounds)] VariableNode),
168 #[serde(rename = "error")]
169 Error(#[rkyv(omit_bounds)] ErrorNode),
170}
171
172#[derive(
174 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
175)]
176#[rkyv(serialize_bounds(
177 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
178))]
179#[rkyv(deserialize_bounds(
180 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
181))]
182#[rkyv(bytecheck(bounds(
183 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
184)))]
185pub struct StandardBlockNode {
186 #[serde(skip_serializing_if = "Option::is_none")]
187 pub depth: Option<u8>,
188 #[serde(skip_serializing_if = "Option::is_none")]
189 pub ordered: Option<bool>,
190 #[serde(skip_serializing_if = "Option::is_none")]
192 pub checked: Option<bool>,
193 #[serde(skip_serializing_if = "Option::is_none")]
195 pub id: Option<String>,
196 #[rkyv(omit_bounds)]
197 pub children: Vec<Node>,
198 pub position: Position,
199}
200
201#[derive(
203 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
204)]
205#[rkyv(serialize_bounds(
206 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
207))]
208#[rkyv(deserialize_bounds(
209 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
210))]
211#[rkyv(bytecheck(bounds(
212 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
213)))]
214pub struct ComponentNode {
215 pub name: String,
216 #[serde(rename = "isInline")]
217 pub is_inline: bool,
218 #[rkyv(omit_bounds)]
219 pub attributes: Vec<AttributeNode>,
220 #[rkyv(omit_bounds)]
221 pub children: Vec<Node>,
222 #[serde(
226 default,
227 rename = "rawContent",
228 skip_serializing_if = "String::is_empty"
229 )]
230 pub raw_content: String,
231 pub position: Position,
232}
233
234#[derive(
236 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
237)]
238#[rkyv(serialize_bounds(
239 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
240))]
241#[rkyv(deserialize_bounds(
242 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
243))]
244#[rkyv(bytecheck(bounds(
245 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
246)))]
247pub struct AttributeNode {
248 pub name: String,
249 #[rkyv(omit_bounds)]
250 pub value: AttributeValue,
251 pub position: Position,
252}
253
254#[derive(
256 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
257)]
258#[rkyv(serialize_bounds(
259 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
260))]
261#[rkyv(deserialize_bounds(
262 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
263))]
264#[rkyv(bytecheck(bounds(
265 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
266)))]
267#[serde(untagged)]
268pub enum AttributeValue {
269 Null,
270 Bool(bool),
271 Number(#[rkyv(with = rkyv_json::AsJsonString)] serde_json::Number),
272 String(String),
273 Array(#[rkyv(with = rkyv_json::AsJsonString)] Vec<serde_json::Value>),
274 Object(#[rkyv(with = rkyv_json::AsJsonString)] serde_json::Map<String, serde_json::Value>),
275 Variable(#[rkyv(omit_bounds)] VariableNode),
276}
277
278#[derive(
280 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
281)]
282#[rkyv(serialize_bounds(
283 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
284))]
285#[rkyv(deserialize_bounds(
286 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
287))]
288#[rkyv(bytecheck(bounds(
289 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
290)))]
291pub struct FootnoteNode {
292 pub label: String,
293 #[rkyv(omit_bounds)]
294 pub children: Vec<Node>,
295 pub position: Position,
296}
297
298#[derive(
300 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
301)]
302#[rkyv(serialize_bounds(
303 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
304))]
305#[rkyv(deserialize_bounds(
306 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
307))]
308#[rkyv(bytecheck(bounds(
309 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
310)))]
311pub struct LinkNode {
312 pub url: String,
313 #[serde(skip_serializing_if = "Option::is_none")]
314 pub title: Option<String>,
315 #[rkyv(omit_bounds)]
316 pub children: Vec<Node>,
317 pub position: Position,
318}
319
320#[derive(
322 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
323)]
324#[rkyv(serialize_bounds(
325 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
326))]
327#[rkyv(deserialize_bounds(
328 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
329))]
330#[rkyv(bytecheck(bounds(
331 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
332)))]
333pub struct ImageNode {
334 pub url: String,
335 #[serde(skip_serializing_if = "Option::is_none")]
336 pub title: Option<String>,
337 #[serde(skip_serializing_if = "Option::is_none")]
338 pub alt: Option<String>,
339 #[rkyv(omit_bounds)]
340 pub children: Vec<Node>,
341 pub position: Position,
342}
343
344#[derive(
346 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
347)]
348pub struct CodeBlockNode {
349 pub value: String,
350 #[serde(skip_serializing_if = "Option::is_none")]
351 pub lang: Option<String>,
352 #[serde(skip_serializing_if = "Option::is_none")]
353 pub meta: Option<String>,
354 #[serde(skip_serializing_if = "Option::is_none")]
356 pub title: Option<String>,
357 #[serde(skip_serializing_if = "Option::is_none")]
359 pub highlight: Option<Vec<u32>>,
360 #[serde(rename = "showLineNumbers", skip_serializing_if = "Option::is_none")]
362 pub show_line_numbers: Option<bool>,
363 #[serde(skip_serializing_if = "Option::is_none")]
365 pub diff: Option<bool>,
366 #[serde(skip_serializing_if = "Option::is_none")]
368 pub caption: Option<String>,
369 pub position: Position,
370}
371
372#[derive(
374 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
375)]
376pub struct TextNode {
377 pub value: String,
378 pub position: Position,
379}
380
381#[derive(
383 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
384)]
385pub struct CodeInlineNode {
386 pub value: String,
387 #[serde(skip_serializing_if = "Option::is_none")]
388 pub lang: Option<String>,
389 pub position: Position,
390}
391
392#[derive(
394 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
395)]
396pub struct VariableNode {
397 pub path: String,
398 pub position: Position,
399}
400
401#[derive(
403 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
404)]
405pub struct ErrorNode {
406 pub message: String,
407 #[serde(rename = "rawContent")]
408 pub raw_content: String,
409 pub position: Position,
410}
411
412#[derive(
414 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
415)]
416pub struct CitationNode {
417 pub keys: Vec<CitationKey>,
418 pub position: Position,
419}
420
421#[derive(
423 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
424)]
425pub struct CitationKey {
426 pub id: String,
427 #[serde(skip_serializing_if = "Option::is_none")]
428 pub prefix: Option<String>,
429 #[serde(skip_serializing_if = "Option::is_none")]
430 pub locator: Option<String>,
431}
432
433#[derive(
435 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
436)]
437pub struct CrossRefNode {
438 pub target: String,
439 pub position: Position,
440}
441
442#[derive(
444 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
445)]
446#[rkyv(serialize_bounds(
447 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
448))]
449#[rkyv(deserialize_bounds(
450 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
451))]
452#[rkyv(bytecheck(bounds(
453 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
454)))]
455pub struct MathNode {
456 pub raw: String,
457 #[rkyv(omit_bounds)]
458 pub tree: MathExpr,
459 pub position: Position,
460}
461
462#[derive(
464 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
465)]
466#[rkyv(serialize_bounds(
467 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
468))]
469#[rkyv(deserialize_bounds(
470 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
471))]
472#[rkyv(bytecheck(bounds(
473 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
474)))]
475pub struct MathDisplayNode {
476 pub raw: String,
477 #[rkyv(omit_bounds)]
478 pub tree: MathExpr,
479 #[serde(skip_serializing_if = "Option::is_none")]
480 pub label: Option<String>,
481 pub position: Position,
482}
483
484#[derive(
490 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
491)]
492pub struct MathOperator {
493 pub symbol: String,
494 pub kind: OperatorKind,
495}
496
497#[derive(
499 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
500)]
501#[serde(rename_all = "snake_case")]
502pub enum OperatorKind {
503 Binary,
504 Relation,
505 Prefix,
506 Postfix,
507 Large,
508 Punctuation,
509}
510
511#[derive(
513 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
514)]
515#[serde(rename_all = "snake_case")]
516pub enum Delimiter {
517 Paren,
518 Bracket,
519 Brace,
520 Angle,
521 Pipe,
522 DoublePipe,
523 Floor,
524 Ceil,
525 None,
526}
527
528#[derive(
530 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
531)]
532#[serde(rename_all = "snake_case")]
533pub enum FracStyle {
534 Display,
535 Text,
536 Auto,
537}
538
539#[derive(
541 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
542)]
543#[serde(rename_all = "snake_case")]
544pub enum LimitStyle {
545 DisplayLimits,
546 Limits,
547 NoLimits,
548}
549
550#[derive(
552 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
553)]
554#[serde(rename_all = "snake_case")]
555pub enum MatrixDelimiters {
556 Plain,
557 Paren,
558 Bracket,
559 Brace,
560 Pipe,
561 DoublePipe,
562}
563
564#[derive(
566 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
567)]
568#[serde(rename_all = "snake_case")]
569pub enum ColumnAlign {
570 Left,
571 Center,
572 Right,
573}
574
575#[derive(
577 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
578)]
579#[serde(rename_all = "snake_case")]
580pub enum MathSpace {
581 Thin,
582 Medium,
583 Thick,
584 Quad,
585 QQuad,
586 NegThin,
587 Custom(String),
588}
589
590#[derive(
592 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
593)]
594#[serde(rename_all = "snake_case")]
595pub enum SmashMode {
596 Top,
597 Bottom,
598 Both,
599}
600
601#[derive(
603 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
604)]
605#[serde(rename_all = "snake_case")]
606pub enum MathStyle {
607 Display,
608 Text,
609 Script,
610 ScriptScript,
611}
612
613#[derive(
615 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
616)]
617#[serde(rename_all = "snake_case")]
618pub enum MathFont {
619 Roman,
620 Bold,
621 Italic,
622 BoldItalic,
623 SansSerif,
624 Monospace,
625 Blackboard,
626 Calligraphic,
627 Fraktur,
628 Script,
629}
630
631#[derive(
633 Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
634)]
635#[serde(rename_all = "snake_case")]
636pub enum AccentKind {
637 Hat,
638 Tilde,
639 Vec,
640 Dot,
641 Ddot,
642 Bar,
643 Acute,
644 Grave,
645 Breve,
646 Check,
647 WideHat,
648 WideTilde,
649}
650
651#[derive(
653 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
654)]
655#[rkyv(serialize_bounds(
656 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
657))]
658#[rkyv(deserialize_bounds(
659 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
660))]
661#[rkyv(bytecheck(bounds(
662 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
663)))]
664pub struct AlignRow {
665 #[rkyv(omit_bounds)]
666 pub cells: Vec<MathExpr>,
667 #[serde(skip_serializing_if = "Option::is_none")]
668 pub label: Option<String>,
669}
670
671#[derive(
673 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
674)]
675#[rkyv(serialize_bounds(
676 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
677))]
678#[rkyv(deserialize_bounds(
679 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
680))]
681#[rkyv(bytecheck(bounds(
682 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
683)))]
684pub struct CaseRow {
685 #[rkyv(omit_bounds)]
686 pub expr: MathExpr,
687 #[rkyv(omit_bounds)]
688 pub condition: Option<MathExpr>,
689}
690
691#[derive(
697 Debug, Clone, PartialEq, Serialize, Deserialize, Archive, rkyv::Serialize, rkyv::Deserialize,
698)]
699#[rkyv(serialize_bounds(
700 __S: rkyv::ser::Writer + rkyv::ser::Allocator + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
701))]
702#[rkyv(deserialize_bounds(
703 __D: rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
704))]
705#[rkyv(bytecheck(bounds(
706 __C: rkyv::validation::ArchiveContext + rkyv::rancor::Fallible<Error: rkyv::rancor::Source>,
707)))]
708#[serde(tag = "type", rename_all = "snake_case")]
709pub enum MathExpr {
710 Ident {
712 value: String,
713 },
714 Number {
715 value: String,
716 },
717 Operator(MathOperator),
718 Text {
719 value: String,
720 },
721
722 Row {
724 #[rkyv(omit_bounds)]
725 children: Vec<MathExpr>,
726 },
727 Fenced {
728 open: Delimiter,
729 close: Delimiter,
730 #[rkyv(omit_bounds)]
731 body: Vec<MathExpr>,
732 },
733
734 Superscript {
736 #[rkyv(omit_bounds)]
737 base: Box<MathExpr>,
738 #[rkyv(omit_bounds)]
739 script: Box<MathExpr>,
740 },
741 Subscript {
742 #[rkyv(omit_bounds)]
743 base: Box<MathExpr>,
744 #[rkyv(omit_bounds)]
745 script: Box<MathExpr>,
746 },
747 Subsuperscript {
748 #[rkyv(omit_bounds)]
749 base: Box<MathExpr>,
750 #[rkyv(omit_bounds)]
751 sub: Box<MathExpr>,
752 #[rkyv(omit_bounds)]
753 sup: Box<MathExpr>,
754 },
755
756 Frac {
758 #[rkyv(omit_bounds)]
759 numerator: Box<MathExpr>,
760 #[rkyv(omit_bounds)]
761 denominator: Box<MathExpr>,
762 style: FracStyle,
763 },
764 Sqrt {
765 #[rkyv(omit_bounds)]
766 index: Option<Box<MathExpr>>,
767 #[rkyv(omit_bounds)]
768 body: Box<MathExpr>,
769 },
770
771 Overline {
773 #[rkyv(omit_bounds)]
774 body: Box<MathExpr>,
775 },
776 Underline {
777 #[rkyv(omit_bounds)]
778 body: Box<MathExpr>,
779 },
780 Overbrace {
781 #[rkyv(omit_bounds)]
782 body: Box<MathExpr>,
783 #[rkyv(omit_bounds)]
784 annotation: Option<Box<MathExpr>>,
785 },
786 Underbrace {
787 #[rkyv(omit_bounds)]
788 body: Box<MathExpr>,
789 #[rkyv(omit_bounds)]
790 annotation: Option<Box<MathExpr>>,
791 },
792 Overset {
793 #[rkyv(omit_bounds)]
794 over: Box<MathExpr>,
795 #[rkyv(omit_bounds)]
796 base: Box<MathExpr>,
797 },
798 Underset {
799 #[rkyv(omit_bounds)]
800 under: Box<MathExpr>,
801 #[rkyv(omit_bounds)]
802 base: Box<MathExpr>,
803 },
804 Accent {
805 kind: AccentKind,
806 #[rkyv(omit_bounds)]
807 body: Box<MathExpr>,
808 },
809
810 BigOperator {
812 op: MathOperator,
813 limits: LimitStyle,
814 #[rkyv(omit_bounds)]
815 lower: Option<Box<MathExpr>>,
816 #[rkyv(omit_bounds)]
817 upper: Option<Box<MathExpr>>,
818 },
819
820 Matrix {
822 #[rkyv(omit_bounds)]
823 rows: Vec<Vec<MathExpr>>,
824 delimiters: MatrixDelimiters,
825 },
826 Cases {
827 #[rkyv(omit_bounds)]
828 rows: Vec<CaseRow>,
829 },
830 Array {
831 columns: Vec<ColumnAlign>,
832 #[rkyv(omit_bounds)]
833 rows: Vec<Vec<MathExpr>>,
834 },
835
836 Align {
838 #[rkyv(omit_bounds)]
839 rows: Vec<AlignRow>,
840 numbered: bool,
841 },
842 Gather {
843 #[rkyv(omit_bounds)]
844 rows: Vec<MathExpr>,
845 numbered: bool,
846 },
847
848 Space(MathSpace),
850 Phantom {
851 #[rkyv(omit_bounds)]
852 body: Box<MathExpr>,
853 },
854 HPhantom {
855 #[rkyv(omit_bounds)]
856 body: Box<MathExpr>,
857 },
858 VPhantom {
859 #[rkyv(omit_bounds)]
860 body: Box<MathExpr>,
861 },
862 Smash {
863 #[rkyv(omit_bounds)]
864 body: Box<MathExpr>,
865 mode: SmashMode,
866 },
867
868 StyleOverride {
870 style: MathStyle,
871 #[rkyv(omit_bounds)]
872 body: Box<MathExpr>,
873 },
874 FontOverride {
875 font: MathFont,
876 #[rkyv(omit_bounds)]
877 body: Box<MathExpr>,
878 },
879 Color {
880 color: String,
881 #[rkyv(omit_bounds)]
882 body: Box<MathExpr>,
883 },
884
885 Chem {
887 value: String,
888 },
889
890 Error {
892 raw: String,
893 message: String,
894 },
895}
896
897impl Node {
898 pub fn children_mut(&mut self) -> Option<&mut Vec<Node>> {
900 match self {
901 Node::Paragraph(b)
902 | Node::Heading(b)
903 | Node::List(b)
904 | Node::ListItem(b)
905 | Node::Blockquote(b)
906 | Node::Html(b)
907 | Node::Table(b)
908 | Node::TableRow(b)
909 | Node::TableCell(b)
910 | Node::Emphasis(b)
911 | Node::Strong(b)
912 | Node::Strikethrough(b)
913 | Node::ThematicBreak(b)
914 | Node::DefinitionList(b)
915 | Node::DefinitionTerm(b)
916 | Node::DefinitionDescription(b) => Some(&mut b.children),
917 Node::Link(l) => Some(&mut l.children),
918 Node::Image(i) => Some(&mut i.children),
919 Node::Component(c) => Some(&mut c.children),
920 Node::FootnoteDefinition(n) => Some(&mut n.children),
921 _ => None,
922 }
923 }
924
925 pub fn children(&self) -> Option<&[Node]> {
927 match self {
928 Node::Paragraph(b)
929 | Node::Heading(b)
930 | Node::List(b)
931 | Node::ListItem(b)
932 | Node::Blockquote(b)
933 | Node::Html(b)
934 | Node::Table(b)
935 | Node::TableRow(b)
936 | Node::TableCell(b)
937 | Node::Emphasis(b)
938 | Node::Strong(b)
939 | Node::Strikethrough(b)
940 | Node::ThematicBreak(b)
941 | Node::DefinitionList(b)
942 | Node::DefinitionTerm(b)
943 | Node::DefinitionDescription(b) => Some(&b.children),
944 Node::Link(l) => Some(&l.children),
945 Node::Image(i) => Some(&i.children),
946 Node::Component(c) => Some(&c.children),
947 Node::FootnoteDefinition(n) => Some(&n.children),
948 _ => None,
949 }
950 }
951}
952
953#[cfg(test)]
954mod tests {
955 use super::*;
956
957 fn pos(line: usize, col: usize, off: usize) -> Point {
958 Point {
959 line,
960 column: col,
961 offset: off,
962 }
963 }
964
965 fn span(sl: usize, sc: usize, so: usize, el: usize, ec: usize, eo: usize) -> Position {
966 Position {
967 start: pos(sl, sc, so),
968 end: pos(el, ec, eo),
969 }
970 }
971
972 #[test]
973 fn root_serializes_type_field() {
974 let root = Root {
975 node_type: RootType::Root,
976 frontmatter: None,
977 children: vec![],
978 position: span(1, 1, 0, 1, 1, 0),
979 };
980 let json = serde_json::to_value(&root).unwrap();
981 assert_eq!(json["type"], "root");
982 assert!(json["frontmatter"].is_null());
983 assert_eq!(json["children"], serde_json::json!([]));
984 }
985
986 #[test]
987 fn component_node_serializes_correctly() {
988 let node = Node::Component(ComponentNode {
989 name: "Badge".into(),
990 is_inline: false,
991 attributes: vec![
992 AttributeNode {
993 name: "status".into(),
994 value: AttributeValue::String("beta".into()),
995 position: span(1, 8, 7, 1, 22, 21),
996 },
997 AttributeNode {
998 name: "active".into(),
999 value: AttributeValue::Bool(true),
1000 position: span(1, 23, 22, 1, 36, 35),
1001 },
1002 ],
1003 children: vec![Node::Text(TextNode {
1004 value: "New Feature".into(),
1005 position: span(1, 37, 36, 1, 48, 47),
1006 })],
1007 raw_content: String::new(),
1008 position: span(1, 1, 0, 1, 55, 54),
1009 });
1010
1011 let json = serde_json::to_value(&node).unwrap();
1012 assert_eq!(json["type"], "component");
1013 assert_eq!(json["name"], "Badge");
1014 assert_eq!(json["isInline"], false);
1015 assert_eq!(json["attributes"][0]["name"], "status");
1016 assert_eq!(json["attributes"][0]["value"], "beta");
1017 assert_eq!(json["attributes"][1]["name"], "active");
1018 assert_eq!(json["attributes"][1]["value"], true);
1019 assert_eq!(json["children"][0]["type"], "text");
1020 assert_eq!(json["children"][0]["value"], "New Feature");
1021 }
1022
1023 #[test]
1024 fn attribute_value_null_serializes_to_null() {
1025 let val = AttributeValue::Null;
1026 let json = serde_json::to_value(&val).unwrap();
1027 assert!(json.is_null());
1028 }
1029
1030 #[test]
1031 fn attribute_value_number() {
1032 let val = AttributeValue::Number(serde_json::Number::from(42));
1033 let json = serde_json::to_value(&val).unwrap();
1034 assert_eq!(json, 42);
1035 }
1036
1037 #[test]
1038 fn attribute_value_json_object() {
1039 let mut map = serde_json::Map::new();
1040 map.insert("type".into(), serde_json::Value::String("bar".into()));
1041 let val = AttributeValue::Object(map);
1042 let json = serde_json::to_value(&val).unwrap();
1043 assert_eq!(json["type"], "bar");
1044 }
1045
1046 #[test]
1047 fn attribute_value_json_array() {
1048 let val = AttributeValue::Array(vec![
1049 serde_json::Value::from(10),
1050 serde_json::Value::from(20),
1051 ]);
1052 let json = serde_json::to_value(&val).unwrap();
1053 assert_eq!(json, serde_json::json!([10, 20]));
1054 }
1055
1056 #[test]
1057 fn variable_node_serializes() {
1058 let node = Node::Variable(VariableNode {
1059 path: "frontmatter.title".into(),
1060 position: span(1, 1, 0, 1, 20, 19),
1061 });
1062 let json = serde_json::to_value(&node).unwrap();
1063 assert_eq!(json["type"], "variable");
1064 assert_eq!(json["path"], "frontmatter.title");
1065 }
1066
1067 #[test]
1068 fn error_node_serializes() {
1069 let node = Node::Error(ErrorNode {
1070 message: "Unclosed tag".into(),
1071 raw_content: "<Notice>".into(),
1072 position: span(1, 1, 0, 1, 9, 8),
1073 });
1074 let json = serde_json::to_value(&node).unwrap();
1075 assert_eq!(json["type"], "error");
1076 assert_eq!(json["message"], "Unclosed tag");
1077 assert_eq!(json["rawContent"], "<Notice>");
1078 }
1079
1080 #[test]
1081 fn standard_block_omits_none_fields() {
1082 let node = Node::Heading(StandardBlockNode {
1083 depth: Some(2),
1084 ordered: None,
1085 checked: None,
1086 id: None,
1087 children: vec![],
1088 position: span(1, 1, 0, 1, 10, 9),
1089 });
1090 let json = serde_json::to_value(&node).unwrap();
1091 assert_eq!(json["depth"], 2);
1092 assert!(json.get("ordered").is_none());
1093 assert!(json.get("checked").is_none());
1094 assert!(json.get("id").is_none());
1095 }
1096
1097 #[test]
1098 fn roundtrip_component_node() {
1099 let original = Node::Component(ComponentNode {
1100 name: "Chart".into(),
1101 is_inline: true,
1102 attributes: vec![],
1103 children: vec![],
1104 raw_content: String::new(),
1105 position: span(1, 1, 0, 1, 10, 9),
1106 });
1107 let serialized = serde_json::to_string(&original).unwrap();
1108 let deserialized: Node = serde_json::from_str(&serialized).unwrap();
1109 assert_eq!(original, deserialized);
1110 }
1111
1112 #[test]
1113 fn code_inline_node_serializes() {
1114 let node = Node::CodeInline(CodeInlineNode {
1115 value: "x + 1".into(),
1116 lang: Some("rust".into()),
1117 position: span(1, 1, 0, 1, 10, 9),
1118 });
1119 let json = serde_json::to_value(&node).unwrap();
1120 assert_eq!(json["type"], "code_inline");
1121 assert_eq!(json["value"], "x + 1");
1122 assert_eq!(json["lang"], "rust");
1123 }
1124
1125 #[test]
1126 fn code_inline_node_omits_lang_when_none() {
1127 let node = Node::CodeInline(CodeInlineNode {
1128 value: "foo()".into(),
1129 lang: None,
1130 position: span(1, 1, 0, 1, 7, 6),
1131 });
1132 let json = serde_json::to_value(&node).unwrap();
1133 assert_eq!(json["type"], "code_inline");
1134 assert!(json.get("lang").is_none());
1135 }
1136
1137 #[test]
1138 fn code_block_node_new_fields_serialize() {
1139 let node = Node::CodeBlock(CodeBlockNode {
1140 value: "fn main() {}".into(),
1141 lang: Some("rust".into()),
1142 meta: None,
1143 title: Some("main.rs".into()),
1144 highlight: Some(vec![1, 3]),
1145 show_line_numbers: Some(true),
1146 diff: None,
1147 caption: None,
1148 position: span(1, 1, 0, 3, 1, 20),
1149 });
1150 let json = serde_json::to_value(&node).unwrap();
1151 assert_eq!(json["type"], "code_block");
1152 assert_eq!(json["title"], "main.rs");
1153 assert_eq!(json["highlight"], serde_json::json!([1, 3]));
1154 assert_eq!(json["showLineNumbers"], true);
1155 assert!(json.get("diff").is_none());
1156 assert!(json.get("caption").is_none());
1157 }
1158
1159 #[test]
1160 fn citation_node_serializes() {
1161 let node = Node::Citation(CitationNode {
1162 keys: vec![
1163 CitationKey {
1164 id: "smith2024".into(),
1165 prefix: Some("see ".into()),
1166 locator: Some("p. 42".into()),
1167 },
1168 CitationKey {
1169 id: "jones2023".into(),
1170 prefix: None,
1171 locator: None,
1172 },
1173 ],
1174 position: span(1, 1, 0, 1, 20, 19),
1175 });
1176 let json = serde_json::to_value(&node).unwrap();
1177 assert_eq!(json["type"], "citation");
1178 assert_eq!(json["keys"][0]["id"], "smith2024");
1179 assert_eq!(json["keys"][0]["prefix"], "see ");
1180 assert_eq!(json["keys"][0]["locator"], "p. 42");
1181 assert_eq!(json["keys"][1]["id"], "jones2023");
1182 assert!(json["keys"][1].get("prefix").is_none());
1183 assert!(json["keys"][1].get("locator").is_none());
1184 }
1185
1186 #[test]
1187 fn cross_ref_node_serializes() {
1188 let node = Node::CrossRef(CrossRefNode {
1189 target: "fig:architecture".into(),
1190 position: span(1, 1, 0, 1, 20, 19),
1191 });
1192 let json = serde_json::to_value(&node).unwrap();
1193 assert_eq!(json["type"], "cross_ref");
1194 assert_eq!(json["target"], "fig:architecture");
1195 }
1196
1197 #[test]
1198 fn math_inline_node_serializes() {
1199 let node = Node::MathInline(MathNode {
1200 raw: "x^2".into(),
1201 tree: MathExpr::Superscript {
1202 base: Box::new(MathExpr::Ident { value: "x".into() }),
1203 script: Box::new(MathExpr::Number { value: "2".into() }),
1204 },
1205 position: span(1, 1, 0, 1, 6, 5),
1206 });
1207 let json = serde_json::to_value(&node).unwrap();
1208 assert_eq!(json["type"], "math_inline");
1209 assert_eq!(json["raw"], "x^2");
1210 assert_eq!(json["tree"]["type"], "superscript");
1211 assert_eq!(json["tree"]["base"]["type"], "ident");
1212 assert_eq!(json["tree"]["base"]["value"], "x");
1213 assert_eq!(json["tree"]["script"]["type"], "number");
1214 assert_eq!(json["tree"]["script"]["value"], "2");
1215 }
1216
1217 #[test]
1218 fn math_display_node_serializes_with_label() {
1219 let node = Node::MathDisplay(MathDisplayNode {
1220 raw: "E = mc^2".into(),
1221 tree: MathExpr::Row {
1222 children: vec![MathExpr::Ident { value: "E".into() }],
1223 },
1224 label: Some("eq:einstein".into()),
1225 position: span(1, 1, 0, 1, 12, 11),
1226 });
1227 let json = serde_json::to_value(&node).unwrap();
1228 assert_eq!(json["type"], "math_display");
1229 assert_eq!(json["raw"], "E = mc^2");
1230 assert_eq!(json["label"], "eq:einstein");
1231 assert_eq!(json["tree"]["type"], "row");
1232 }
1233
1234 #[test]
1235 fn math_display_node_omits_label_when_none() {
1236 let node = Node::MathDisplay(MathDisplayNode {
1237 raw: "x".into(),
1238 tree: MathExpr::Ident { value: "x".into() },
1239 label: None,
1240 position: span(1, 1, 0, 1, 3, 2),
1241 });
1242 let json = serde_json::to_value(&node).unwrap();
1243 assert!(json.get("label").is_none());
1244 }
1245
1246 #[test]
1247 fn definition_list_variants_have_children() {
1248 let dl = Node::DefinitionList(StandardBlockNode {
1249 depth: None,
1250 ordered: None,
1251 checked: None,
1252 id: None,
1253 children: vec![Node::DefinitionTerm(StandardBlockNode {
1254 depth: None,
1255 ordered: None,
1256 checked: None,
1257 id: None,
1258 children: vec![Node::Text(TextNode {
1259 value: "Term".into(),
1260 position: span(1, 1, 0, 1, 5, 4),
1261 })],
1262 position: span(1, 1, 0, 1, 5, 4),
1263 })],
1264 position: span(1, 1, 0, 2, 1, 10),
1265 });
1266 let json = serde_json::to_value(&dl).unwrap();
1267 assert_eq!(json["type"], "definition_list");
1268 assert_eq!(json["children"][0]["type"], "definition_term");
1269 assert_eq!(json["children"][0]["children"][0]["value"], "Term");
1270 }
1271
1272 #[test]
1273 fn definition_list_children_accessible() {
1274 let node = Node::DefinitionList(StandardBlockNode {
1275 depth: None,
1276 ordered: None,
1277 checked: None,
1278 id: None,
1279 children: vec![],
1280 position: span(1, 1, 0, 1, 1, 0),
1281 });
1282 assert!(node.children().is_some());
1283 }
1284
1285 #[test]
1286 fn math_frac_roundtrip() {
1287 let expr = MathExpr::Frac {
1288 numerator: Box::new(MathExpr::Number { value: "1".into() }),
1289 denominator: Box::new(MathExpr::Number { value: "2".into() }),
1290 style: FracStyle::Auto,
1291 };
1292 let serialized = serde_json::to_string(&expr).unwrap();
1293 let deserialized: MathExpr = serde_json::from_str(&serialized).unwrap();
1294 assert_eq!(expr, deserialized);
1295 }
1296
1297 #[test]
1298 fn math_error_variant_serializes() {
1299 let expr = MathExpr::Error {
1300 raw: r"\unknown".into(),
1301 message: "Unknown command".into(),
1302 };
1303 let json = serde_json::to_value(&expr).unwrap();
1304 assert_eq!(json["type"], "error");
1305 assert_eq!(json["raw"], r"\unknown");
1306 assert_eq!(json["message"], "Unknown command");
1307 }
1308}