markdown_ppp/ast/convert.rs
1//! Conversion utilities for AST nodes with user data
2//!
3//! This module provides traits and functions for converting between different
4//! AST representations with and without user data.
5
6use super::generic;
7use super::*;
8
9// ——————————————————————————————————————————————————————————————————————————
10// Conversion traits
11// ——————————————————————————————————————————————————————————————————————————
12
13/// Add user data to an AST node
14pub trait WithData<T>: Sized {
15 /// The type with user data attached
16 type WithDataType;
17
18 /// Add user data to this AST node
19 fn with_data(self, data: T) -> Self::WithDataType;
20
21 /// Add default user data to this AST node
22 fn with_default_data(self) -> Self::WithDataType
23 where
24 T: Default,
25 {
26 self.with_data(T::default())
27 }
28}
29
30/// Remove user data from an AST node
31pub trait StripData<T>: Sized {
32 /// The type without user data
33 type StrippedType;
34
35 /// Remove user data from this AST node
36 fn strip_data(self) -> Self::StrippedType;
37}
38
39/// Transform user data type in an AST node
40/// NOTE: Replaced by visitor-based approach in `map_data_visitor` module
41pub trait MapData<T, U>: Sized {
42 /// The type with the new user data type
43 type MappedType;
44
45 /// Transform user data using the provided function
46 fn map_data<F>(self, f: F) -> Self::MappedType
47 where
48 F: FnMut(T) -> U;
49}
50
51// ——————————————————————————————————————————————————————————————————————————
52// Conversion functions for regular AST -> generic AST
53// ——————————————————————————————————————————————————————————————————————————
54
55impl<T: Default> WithData<T> for Document {
56 type WithDataType = generic::Document<T>;
57
58 fn with_data(self, data: T) -> Self::WithDataType {
59 generic::Document {
60 blocks: self
61 .blocks
62 .into_iter()
63 .map(|b| b.with_data(T::default()))
64 .collect(),
65 user_data: data,
66 }
67 }
68}
69
70impl<T: Default> WithData<T> for Block {
71 type WithDataType = generic::Block<T>;
72
73 fn with_data(self, data: T) -> Self::WithDataType {
74 match self {
75 Block::Paragraph(content) => generic::Block::Paragraph {
76 content: content
77 .into_iter()
78 .map(|i| i.with_data(T::default()))
79 .collect(),
80 user_data: data,
81 },
82 Block::Heading(heading) => generic::Block::Heading(heading.with_data(data)),
83 Block::ThematicBreak => generic::Block::ThematicBreak { user_data: data },
84 Block::BlockQuote(blocks) => generic::Block::BlockQuote {
85 blocks: blocks
86 .into_iter()
87 .map(|b| b.with_data(T::default()))
88 .collect(),
89 user_data: data,
90 },
91 Block::List(list) => generic::Block::List(list.with_data(data)),
92 Block::CodeBlock(code_block) => generic::Block::CodeBlock(code_block.with_data(data)),
93 Block::HtmlBlock(content) => generic::Block::HtmlBlock {
94 content,
95 user_data: data,
96 },
97 Block::Definition(def) => generic::Block::Definition(def.with_data(data)),
98 Block::Table(table) => generic::Block::Table(table.with_data(data)),
99 Block::FootnoteDefinition(footnote) => {
100 generic::Block::FootnoteDefinition(footnote.with_data(data))
101 }
102 Block::GitHubAlert(alert) => generic::Block::GitHubAlert(alert.with_data(data)),
103 Block::Empty => generic::Block::Empty { user_data: data },
104 }
105 }
106}
107
108impl<T: Default> WithData<T> for Inline {
109 type WithDataType = generic::Inline<T>;
110
111 fn with_data(self, data: T) -> Self::WithDataType {
112 match self {
113 Inline::Text(content) => generic::Inline::Text {
114 content,
115 user_data: data,
116 },
117 Inline::LineBreak => generic::Inline::LineBreak { user_data: data },
118 Inline::Code(content) => generic::Inline::Code {
119 content,
120 user_data: data,
121 },
122 Inline::Html(content) => generic::Inline::Html {
123 content,
124 user_data: data,
125 },
126 Inline::Link(link) => generic::Inline::Link(link.with_data(data)),
127 Inline::LinkReference(link_ref) => {
128 generic::Inline::LinkReference(link_ref.with_data(data))
129 }
130 Inline::Image(image) => generic::Inline::Image(image.with_data(data)),
131 Inline::Emphasis(content) => generic::Inline::Emphasis {
132 content: content
133 .into_iter()
134 .map(|i| i.with_data(T::default()))
135 .collect(),
136 user_data: data,
137 },
138 Inline::Strong(content) => generic::Inline::Strong {
139 content: content
140 .into_iter()
141 .map(|i| i.with_data(T::default()))
142 .collect(),
143 user_data: data,
144 },
145 Inline::Strikethrough(content) => generic::Inline::Strikethrough {
146 content: content
147 .into_iter()
148 .map(|i| i.with_data(T::default()))
149 .collect(),
150 user_data: data,
151 },
152 Inline::Autolink(url) => generic::Inline::Autolink {
153 url,
154 user_data: data,
155 },
156 Inline::FootnoteReference(label) => generic::Inline::FootnoteReference {
157 label,
158 user_data: data,
159 },
160 Inline::Empty => generic::Inline::Empty { user_data: data },
161 }
162 }
163}
164
165impl<T: Default> WithData<T> for Heading {
166 type WithDataType = generic::Heading<T>;
167
168 fn with_data(self, data: T) -> Self::WithDataType {
169 generic::Heading {
170 kind: self.kind,
171 content: self
172 .content
173 .into_iter()
174 .map(|i| i.with_data(T::default()))
175 .collect(),
176 user_data: data,
177 }
178 }
179}
180
181impl<T: Default> WithData<T> for List {
182 type WithDataType = generic::List<T>;
183
184 fn with_data(self, data: T) -> Self::WithDataType {
185 generic::List {
186 kind: generic::ListKind::from(self.kind),
187 items: self
188 .items
189 .into_iter()
190 .map(|i| i.with_data(T::default()))
191 .collect(),
192 user_data: data,
193 }
194 }
195}
196
197impl<T: Default> WithData<T> for ListItem {
198 type WithDataType = generic::ListItem<T>;
199
200 fn with_data(self, data: T) -> Self::WithDataType {
201 generic::ListItem {
202 task: self.task,
203 blocks: self
204 .blocks
205 .into_iter()
206 .map(|b| b.with_data(T::default()))
207 .collect(),
208 user_data: data,
209 }
210 }
211}
212
213impl<T: Default> WithData<T> for CodeBlock {
214 type WithDataType = generic::CodeBlock<T>;
215
216 fn with_data(self, data: T) -> Self::WithDataType {
217 generic::CodeBlock {
218 kind: self.kind,
219 literal: self.literal,
220 user_data: data,
221 }
222 }
223}
224
225impl<T: Default> WithData<T> for LinkDefinition {
226 type WithDataType = generic::LinkDefinition<T>;
227
228 fn with_data(self, data: T) -> Self::WithDataType {
229 generic::LinkDefinition {
230 label: self
231 .label
232 .into_iter()
233 .map(|i| i.with_data(T::default()))
234 .collect(),
235 destination: self.destination,
236 title: self.title,
237 user_data: data,
238 }
239 }
240}
241
242impl<T: Default> WithData<T> for Table {
243 type WithDataType = generic::Table<T>;
244
245 fn with_data(self, data: T) -> Self::WithDataType {
246 generic::Table {
247 rows: self
248 .rows
249 .into_iter()
250 .map(|row| {
251 row.into_iter()
252 .map(|cell| {
253 cell.into_iter()
254 .map(|i| i.with_data(T::default()))
255 .collect()
256 })
257 .collect()
258 })
259 .collect(),
260 alignments: self.alignments,
261 user_data: data,
262 }
263 }
264}
265
266impl<T: Default> WithData<T> for FootnoteDefinition {
267 type WithDataType = generic::FootnoteDefinition<T>;
268
269 fn with_data(self, data: T) -> Self::WithDataType {
270 generic::FootnoteDefinition {
271 label: self.label,
272 blocks: self
273 .blocks
274 .into_iter()
275 .map(|b| b.with_data(T::default()))
276 .collect(),
277 user_data: data,
278 }
279 }
280}
281
282impl<T: Default> WithData<T> for GitHubAlert {
283 type WithDataType = generic::GitHubAlertNode<T>;
284
285 fn with_data(self, data: T) -> Self::WithDataType {
286 generic::GitHubAlertNode {
287 alert_type: self.alert_type,
288 blocks: self
289 .blocks
290 .into_iter()
291 .map(|b| b.with_data(T::default()))
292 .collect(),
293 user_data: data,
294 }
295 }
296}
297
298impl<T: Default> WithData<T> for Link {
299 type WithDataType = generic::Link<T>;
300
301 fn with_data(self, data: T) -> Self::WithDataType {
302 generic::Link {
303 destination: self.destination,
304 title: self.title,
305 children: self
306 .children
307 .into_iter()
308 .map(|i| i.with_data(T::default()))
309 .collect(),
310 user_data: data,
311 }
312 }
313}
314
315impl<T: Default> WithData<T> for Image {
316 type WithDataType = generic::Image<T>;
317
318 fn with_data(self, data: T) -> Self::WithDataType {
319 generic::Image {
320 destination: self.destination,
321 title: self.title,
322 alt: self.alt,
323 user_data: data,
324 }
325 }
326}
327
328impl<T: Default> WithData<T> for LinkReference {
329 type WithDataType = generic::LinkReference<T>;
330
331 fn with_data(self, data: T) -> Self::WithDataType {
332 generic::LinkReference {
333 label: self
334 .label
335 .into_iter()
336 .map(|i| i.with_data(T::default()))
337 .collect(),
338 text: self
339 .text
340 .into_iter()
341 .map(|i| i.with_data(T::default()))
342 .collect(),
343 user_data: data,
344 }
345 }
346}
347
348// ——————————————————————————————————————————————————————————————————————————
349// Conversion functions for generic AST -> regular AST
350// ——————————————————————————————————————————————————————————————————————————
351
352impl<T> StripData<T> for generic::Document<T> {
353 type StrippedType = Document;
354
355 fn strip_data(self) -> Self::StrippedType {
356 Document {
357 blocks: self.blocks.into_iter().map(|b| b.strip_data()).collect(),
358 }
359 }
360}
361
362impl<T> StripData<T> for generic::Block<T> {
363 type StrippedType = Block;
364
365 fn strip_data(self) -> Self::StrippedType {
366 match self {
367 generic::Block::Paragraph { content, .. } => {
368 Block::Paragraph(content.into_iter().map(|i| i.strip_data()).collect())
369 }
370 generic::Block::Heading(heading) => Block::Heading(heading.strip_data()),
371 generic::Block::ThematicBreak { .. } => Block::ThematicBreak,
372 generic::Block::BlockQuote { blocks, .. } => {
373 Block::BlockQuote(blocks.into_iter().map(|b| b.strip_data()).collect())
374 }
375 generic::Block::List(list) => Block::List(list.strip_data()),
376 generic::Block::CodeBlock(code_block) => Block::CodeBlock(code_block.strip_data()),
377 generic::Block::HtmlBlock { content, .. } => Block::HtmlBlock(content),
378 generic::Block::Definition(def) => Block::Definition(def.strip_data()),
379 generic::Block::Table(table) => Block::Table(table.strip_data()),
380 generic::Block::FootnoteDefinition(footnote) => {
381 Block::FootnoteDefinition(footnote.strip_data())
382 }
383 generic::Block::GitHubAlert(alert) => Block::GitHubAlert(alert.strip_data()),
384 generic::Block::Empty { .. } => Block::Empty,
385 }
386 }
387}
388
389impl<T> StripData<T> for generic::Inline<T> {
390 type StrippedType = Inline;
391
392 fn strip_data(self) -> Self::StrippedType {
393 match self {
394 generic::Inline::Text { content, .. } => Inline::Text(content),
395 generic::Inline::LineBreak { .. } => Inline::LineBreak,
396 generic::Inline::Code { content, .. } => Inline::Code(content),
397 generic::Inline::Html { content, .. } => Inline::Html(content),
398 generic::Inline::Link(link) => Inline::Link(link.strip_data()),
399 generic::Inline::LinkReference(link_ref) => {
400 Inline::LinkReference(link_ref.strip_data())
401 }
402 generic::Inline::Image(image) => Inline::Image(image.strip_data()),
403 generic::Inline::Emphasis { content, .. } => {
404 Inline::Emphasis(content.into_iter().map(|i| i.strip_data()).collect())
405 }
406 generic::Inline::Strong { content, .. } => {
407 Inline::Strong(content.into_iter().map(|i| i.strip_data()).collect())
408 }
409 generic::Inline::Strikethrough { content, .. } => {
410 Inline::Strikethrough(content.into_iter().map(|i| i.strip_data()).collect())
411 }
412 generic::Inline::Autolink { url, .. } => Inline::Autolink(url),
413 generic::Inline::FootnoteReference { label, .. } => Inline::FootnoteReference(label),
414 generic::Inline::Empty { .. } => Inline::Empty,
415 }
416 }
417}
418
419impl<T> StripData<T> for generic::Heading<T> {
420 type StrippedType = Heading;
421
422 fn strip_data(self) -> Self::StrippedType {
423 Heading {
424 kind: self.kind,
425 content: self.content.into_iter().map(|i| i.strip_data()).collect(),
426 }
427 }
428}
429
430impl<T> StripData<T> for generic::List<T> {
431 type StrippedType = List;
432
433 fn strip_data(self) -> Self::StrippedType {
434 List {
435 kind: self.kind.into(),
436 items: self.items.into_iter().map(|i| i.strip_data()).collect(),
437 }
438 }
439}
440
441impl<T> StripData<T> for generic::ListItem<T> {
442 type StrippedType = ListItem;
443
444 fn strip_data(self) -> Self::StrippedType {
445 ListItem {
446 task: self.task,
447 blocks: self.blocks.into_iter().map(|b| b.strip_data()).collect(),
448 }
449 }
450}
451
452impl<T> StripData<T> for generic::CodeBlock<T> {
453 type StrippedType = CodeBlock;
454
455 fn strip_data(self) -> Self::StrippedType {
456 CodeBlock {
457 kind: self.kind,
458 literal: self.literal,
459 }
460 }
461}
462
463impl<T> StripData<T> for generic::LinkDefinition<T> {
464 type StrippedType = LinkDefinition;
465
466 fn strip_data(self) -> Self::StrippedType {
467 LinkDefinition {
468 label: self.label.into_iter().map(|i| i.strip_data()).collect(),
469 destination: self.destination,
470 title: self.title,
471 }
472 }
473}
474
475impl<T> StripData<T> for generic::Table<T> {
476 type StrippedType = Table;
477
478 fn strip_data(self) -> Self::StrippedType {
479 Table {
480 rows: self
481 .rows
482 .into_iter()
483 .map(|row| {
484 row.into_iter()
485 .map(|cell| cell.into_iter().map(|i| i.strip_data()).collect())
486 .collect()
487 })
488 .collect(),
489 alignments: self.alignments,
490 }
491 }
492}
493
494impl<T> StripData<T> for generic::FootnoteDefinition<T> {
495 type StrippedType = FootnoteDefinition;
496
497 fn strip_data(self) -> Self::StrippedType {
498 FootnoteDefinition {
499 label: self.label,
500 blocks: self.blocks.into_iter().map(|b| b.strip_data()).collect(),
501 }
502 }
503}
504
505impl<T> StripData<T> for generic::GitHubAlertNode<T> {
506 type StrippedType = GitHubAlert;
507
508 fn strip_data(self) -> Self::StrippedType {
509 GitHubAlert {
510 alert_type: self.alert_type,
511 blocks: self.blocks.into_iter().map(|b| b.strip_data()).collect(),
512 }
513 }
514}
515
516impl<T> StripData<T> for generic::Link<T> {
517 type StrippedType = Link;
518
519 fn strip_data(self) -> Self::StrippedType {
520 Link {
521 destination: self.destination,
522 title: self.title,
523 children: self.children.into_iter().map(|i| i.strip_data()).collect(),
524 }
525 }
526}
527
528impl<T> StripData<T> for generic::Image<T> {
529 type StrippedType = Image;
530
531 fn strip_data(self) -> Self::StrippedType {
532 Image {
533 destination: self.destination,
534 title: self.title,
535 alt: self.alt,
536 }
537 }
538}
539
540impl<T> StripData<T> for generic::LinkReference<T> {
541 type StrippedType = LinkReference;
542
543 fn strip_data(self) -> Self::StrippedType {
544 LinkReference {
545 label: self.label.into_iter().map(|i| i.strip_data()).collect(),
546 text: self.text.into_iter().map(|i| i.strip_data()).collect(),
547 }
548 }
549}
550
551// ——————————————————————————————————————————————————————————————————————————
552// MapData implementations (transform user data type)
553// NOTE: Disabled due to compiler recursion limits
554// ——————————————————————————————————————————————————————————————————————————
555
556/*
557// Temporarily commented out due to recursion limit issues
558impl<T, U> MapData<T, U> for generic::Document<T> {
559 type MappedType = generic::Document<U>;
560
561 fn map_data<F>(self, mut f: F) -> Self::MappedType
562 where
563 F: FnMut(T) -> U,
564 {
565 generic::Document {
566 blocks: self.blocks.into_iter().map(|b| b.map_data(&mut f)).collect(),
567 user_data: f(self.user_data),
568 }
569 }
570}
571
572impl<T, U> MapData<T, U> for generic::Block<T> {
573 type MappedType = generic::Block<U>;
574
575 fn map_data<F>(self, mut f: F) -> Self::MappedType
576 where
577 F: FnMut(T) -> U,
578 {
579 match self {
580 generic::Block::Paragraph { content, user_data } => generic::Block::Paragraph {
581 content: content.into_iter().map(|i| i.map_data(&mut f)).collect(),
582 user_data: f(user_data),
583 },
584 generic::Block::Heading(heading) => generic::Block::Heading(heading.map_data(f)),
585 generic::Block::ThematicBreak { user_data } => generic::Block::ThematicBreak { user_data: f(user_data) },
586 generic::Block::BlockQuote { blocks, user_data } => generic::Block::BlockQuote {
587 blocks: blocks.into_iter().map(|b| b.map_data(&mut f)).collect(),
588 user_data: f(user_data),
589 },
590 generic::Block::List(list) => generic::Block::List(list.map_data(f)),
591 generic::Block::CodeBlock(code_block) => generic::Block::CodeBlock(code_block.map_data(f)),
592 generic::Block::HtmlBlock { content, user_data } => generic::Block::HtmlBlock {
593 content,
594 user_data: f(user_data),
595 },
596 generic::Block::Definition(def) => generic::Block::Definition(def.map_data(f)),
597 generic::Block::Table(table) => generic::Block::Table(table.map_data(f)),
598 generic::Block::FootnoteDefinition(footnote) => generic::Block::FootnoteDefinition(footnote.map_data(f)),
599 generic::Block::GitHubAlert(alert) => generic::Block::GitHubAlert(alert.map_data(f)),
600 generic::Block::Empty { user_data } => generic::Block::Empty { user_data: f(user_data) },
601 }
602 }
603}
604
605impl<T, U> MapData<T, U> for generic::Inline<T> {
606 type MappedType = generic::Inline<U>;
607
608 fn map_data<F>(self, mut f: F) -> Self::MappedType
609 where
610 F: FnMut(T) -> U,
611 {
612 match self {
613 generic::Inline::Text { content, user_data } => generic::Inline::Text {
614 content,
615 user_data: f(user_data),
616 },
617 generic::Inline::LineBreak { user_data } => generic::Inline::LineBreak { user_data: f(user_data) },
618 generic::Inline::Code { content, user_data } => generic::Inline::Code {
619 content,
620 user_data: f(user_data),
621 },
622 generic::Inline::Html { content, user_data } => generic::Inline::Html {
623 content,
624 user_data: f(user_data),
625 },
626 generic::Inline::Link(link) => generic::Inline::Link(link.map_data(f)),
627 generic::Inline::LinkReference(link_ref) => generic::Inline::LinkReference(link_ref.map_data(f)),
628 generic::Inline::Image(image) => generic::Inline::Image(image.map_data(f)),
629 generic::Inline::Emphasis { content, user_data } => generic::Inline::Emphasis {
630 content: content.into_iter().map(|i| i.map_data(&mut f)).collect(),
631 user_data: f(user_data),
632 },
633 generic::Inline::Strong { content, user_data } => generic::Inline::Strong {
634 content: content.into_iter().map(|i| i.map_data(&mut f)).collect(),
635 user_data: f(user_data),
636 },
637 generic::Inline::Strikethrough { content, user_data } => generic::Inline::Strikethrough {
638 content: content.into_iter().map(|i| i.map_data(&mut f)).collect(),
639 user_data: f(user_data),
640 },
641 generic::Inline::Autolink { url, user_data } => generic::Inline::Autolink {
642 url,
643 user_data: f(user_data),
644 },
645 generic::Inline::FootnoteReference { label, user_data } => generic::Inline::FootnoteReference {
646 label,
647 user_data: f(user_data),
648 },
649 generic::Inline::Empty { user_data } => generic::Inline::Empty { user_data: f(user_data) },
650 }
651 }
652}
653
654// Implementation for other types would follow similar patterns...
655// For brevity, I'll implement a few key ones
656
657impl<T, U> MapData<T, U> for generic::Heading<T> {
658 type MappedType = generic::Heading<U>;
659
660 fn map_data<F>(self, mut f: F) -> Self::MappedType
661 where
662 F: FnMut(T) -> U,
663 {
664 generic::Heading {
665 kind: self.kind,
666 content: self.content.into_iter().map(|i| i.map_data(&mut f)).collect(),
667 user_data: f(self.user_data),
668 }
669 }
670}
671
672impl<T, U> MapData<T, U> for generic::List<T> {
673 type MappedType = generic::List<U>;
674
675 fn map_data<F>(self, mut f: F) -> Self::MappedType
676 where
677 F: FnMut(T) -> U,
678 {
679 generic::List {
680 kind: self.kind,
681 items: self.items.into_iter().map(|i| i.map_data(&mut f)).collect(),
682 user_data: f(self.user_data),
683 }
684 }
685}
686
687impl<T, U> MapData<T, U> for generic::ListItem<T> {
688 type MappedType = generic::ListItem<U>;
689
690 fn map_data<F>(self, mut f: F) -> Self::MappedType
691 where
692 F: FnMut(T) -> U,
693 {
694 generic::ListItem {
695 task: self.task,
696 blocks: self.blocks.into_iter().map(|b| b.map_data(&mut f)).collect(),
697 user_data: f(self.user_data),
698 }
699 }
700}
701
702impl<T, U> MapData<T, U> for generic::Link<T> {
703 type MappedType = generic::Link<U>;
704
705 fn map_data<F>(self, mut f: F) -> Self::MappedType
706 where
707 F: FnMut(T) -> U,
708 {
709 generic::Link {
710 destination: self.destination,
711 title: self.title,
712 children: self.children.into_iter().map(|i| i.map_data(&mut f)).collect(),
713 user_data: f(self.user_data),
714 }
715 }
716}
717
718impl<T, U> MapData<T, U> for generic::Image<T> {
719 type MappedType = generic::Image<U>;
720
721 fn map_data<F>(self, mut f: F) -> Self::MappedType
722 where
723 F: FnMut(T) -> U,
724 {
725 generic::Image {
726 destination: self.destination,
727 title: self.title,
728 alt: self.alt,
729 user_data: f(self.user_data),
730 }
731 }
732}
733
734impl<T, U> MapData<T, U> for generic::LinkReference<T> {
735 type MappedType = generic::LinkReference<U>;
736
737 fn map_data<F>(self, mut f: F) -> Self::MappedType
738 where
739 F: FnMut(T) -> U,
740 {
741 generic::LinkReference {
742 label: self.label.into_iter().map(|i| i.map_data(&mut f)).collect(),
743 text: self.text.into_iter().map(|i| i.map_data(&mut f)).collect(),
744 user_data: f(self.user_data),
745 }
746 }
747}
748
749impl<T, U> MapData<T, U> for generic::CodeBlock<T> {
750 type MappedType = generic::CodeBlock<U>;
751
752 fn map_data<F>(self, mut f: F) -> Self::MappedType
753 where
754 F: FnMut(T) -> U,
755 {
756 generic::CodeBlock {
757 kind: self.kind,
758 literal: self.literal,
759 user_data: f(self.user_data),
760 }
761 }
762}
763
764impl<T, U> MapData<T, U> for generic::Table<T> {
765 type MappedType = generic::Table<U>;
766
767 fn map_data<F>(self, mut f: F) -> Self::MappedType
768 where
769 F: FnMut(T) -> U,
770 {
771 generic::Table {
772 rows: self.rows.into_iter().map(|row| {
773 row.into_iter().map(|cell| {
774 cell.into_iter().map(|i| i.map_data(&mut f)).collect()
775 }).collect()
776 }).collect(),
777 alignments: self.alignments,
778 user_data: f(self.user_data),
779 }
780 }
781}
782
783impl<T, U> MapData<T, U> for generic::FootnoteDefinition<T> {
784 type MappedType = generic::FootnoteDefinition<U>;
785
786 fn map_data<F>(self, mut f: F) -> Self::MappedType
787 where
788 F: FnMut(T) -> U,
789 {
790 generic::FootnoteDefinition {
791 label: self.label,
792 blocks: self.blocks.into_iter().map(|b| b.map_data(&mut f)).collect(),
793 user_data: f(self.user_data),
794 }
795 }
796}
797
798impl<T, U> MapData<T, U> for generic::GitHubAlertNode<T> {
799 type MappedType = generic::GitHubAlertNode<U>;
800
801 fn map_data<F>(self, mut f: F) -> Self::MappedType
802 where
803 F: FnMut(T) -> U,
804 {
805 generic::GitHubAlertNode {
806 alert_type: self.alert_type,
807 blocks: self.blocks.into_iter().map(|b| b.map_data(&mut f)).collect(),
808 user_data: f(self.user_data),
809 }
810 }
811}
812
813impl<T, U> MapData<T, U> for generic::LinkDefinition<T> {
814 type MappedType = generic::LinkDefinition<U>;
815
816 fn map_data<F>(self, mut f: F) -> Self::MappedType
817 where
818 F: FnMut(T) -> U,
819 {
820 generic::LinkDefinition {
821 label: self.label.into_iter().map(|i| i.map_data(&mut f)).collect(),
822 destination: self.destination,
823 title: self.title,
824 user_data: f(self.user_data),
825 }
826 }
827}
828*/
829
830// End of MapData implementations - commented out due to recursion limits
831
832// ——————————————————————————————————————————————————————————————————————————
833// Helper functions
834// ——————————————————————————————————————————————————————————————————————————
835
836/// Convert from regular AST to generic AST with unit type
837pub fn to_generic(doc: Document) -> generic::Document<()> {
838 doc.with_default_data()
839}
840
841/// Convert from generic AST with unit type to regular AST
842pub fn from_generic(doc: generic::Document<()>) -> Document {
843 doc.strip_data()
844}
845
846// Conversion between ListKind variants
847impl From<ListKind> for generic::ListKind {
848 fn from(kind: ListKind) -> Self {
849 match kind {
850 ListKind::Ordered(opts) => generic::ListKind::Ordered(opts),
851 ListKind::Bullet(bullet) => generic::ListKind::Bullet(bullet),
852 }
853 }
854}
855
856impl From<generic::ListKind> for ListKind {
857 fn from(kind: generic::ListKind) -> Self {
858 match kind {
859 generic::ListKind::Ordered(opts) => ListKind::Ordered(opts),
860 generic::ListKind::Bullet(bullet) => ListKind::Bullet(bullet),
861 }
862 }
863}