asciidoc_parser/document/
document.rs1use std::{marker::PhantomData, slice::Iter};
4
5use self_cell::self_cell;
6
7use crate::{
8 Parser, Span,
9 attributes::Attrlist,
10 blocks::{Block, ContentModel, IsBlock, parse_utils::parse_blocks_until},
11 document::Header,
12 parser::SourceMap,
13 strings::CowStr,
14 warnings::Warning,
15};
16
17#[derive(Eq, PartialEq)]
30pub struct Document<'src> {
31 internal: Internal,
32 _phantom: PhantomData<&'src ()>,
33}
34
35#[derive(Debug, Eq, PartialEq)]
38struct InternalDependent<'src> {
39 header: Header<'src>,
40 blocks: Vec<Block<'src>>,
41 source: Span<'src>,
42 warnings: Vec<Warning<'src>>,
43 source_map: SourceMap,
44}
45
46self_cell! {
47 struct Internal {
49 owner: String,
50 #[covariant]
51 dependent: InternalDependent,
52 }
53 impl {Debug, Eq, PartialEq}
54}
55
56impl<'src> Document<'src> {
57 pub(crate) fn parse(source: &str, source_map: SourceMap, parser: &mut Parser) -> Self {
58 let owned_source = source.to_string();
59
60 let internal = Internal::new(owned_source, |owned_src| {
61 let source = Span::new(owned_src);
62
63 let mi = Header::parse(source, parser);
64 let next = mi.item.after;
65
66 let header = mi.item.item;
67 let mut warnings = mi.warnings;
68
69 let mut maw_blocks = parse_blocks_until(next, |_| false, parser);
70
71 if !maw_blocks.warnings.is_empty() {
72 warnings.append(&mut maw_blocks.warnings);
73 }
74
75 InternalDependent {
76 header,
77 blocks: maw_blocks.item.item,
78 source: source.trim_trailing_whitespace(),
79 warnings,
80 source_map,
81 }
82 });
83
84 Self {
85 internal,
86 _phantom: PhantomData,
87 }
88 }
89
90 pub fn header(&self) -> &Header<'_> {
92 &self.internal.borrow_dependent().header
93 }
94
95 pub fn warnings(&self) -> Iter<'_, Warning<'_>> {
97 self.internal.borrow_dependent().warnings.iter()
98 }
99
100 pub fn span(&self) -> Span<'_> {
102 self.internal.borrow_dependent().source
103 }
104
105 pub fn source_map(&self) -> &SourceMap {
107 &self.internal.borrow_dependent().source_map
108 }
109}
110
111impl<'src> IsBlock<'src> for Document<'src> {
112 fn content_model(&self) -> ContentModel {
113 ContentModel::Compound
114 }
115
116 fn raw_context(&self) -> CowStr<'src> {
117 "document".into()
118 }
119
120 fn nested_blocks(&'src self) -> Iter<'src, Block<'src>> {
121 self.internal.borrow_dependent().blocks.iter()
122 }
123
124 fn title_source(&'src self) -> Option<Span<'src>> {
125 None
127 }
128
129 fn title(&self) -> Option<&str> {
130 None
132 }
133
134 fn anchor(&'src self) -> Option<Span<'src>> {
135 None
136 }
137
138 fn attrlist(&'src self) -> Option<&'src Attrlist<'src>> {
139 None
141 }
142}
143
144impl std::fmt::Debug for Document<'_> {
145 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146 let dependent = self.internal.borrow_dependent();
147 f.debug_struct("Document")
148 .field("header", &dependent.header)
149 .field("blocks", &dependent.blocks)
150 .field("source", &dependent.source)
151 .field("warnings", &dependent.warnings)
152 .field("source_map", &dependent.source_map)
153 .finish()
154 }
155}