1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use super::compose;
use super::doc::*;
use super::normalize;
use super::schema::*;
use super::{Schema, Track};
use super::stepper::*;
use super::writer::*;
use failure::Error;
use std::borrow::ToOwned;
use std::cmp;
use std::collections::{HashMap, HashSet};
use term_painter::Attr::*;
use term_painter::Color::*;
use term_painter::ToStyle;
#[derive(Clone)]
pub struct ValidateContext {
stack: Vec<Attrs>,
carets: HashSet<String>,
}
impl ValidateContext {
pub fn new() -> ValidateContext {
ValidateContext {
stack: vec![],
carets: hashset![],
}
}
}
pub fn validate_doc_span(ctx: &mut ValidateContext, span: &DocSpan) -> Result<(), Error> {
for elem in span {
match *elem {
DocGroup(ref attrs, ref span) => {
if attrs["tag"] == "caret" {
if !ctx.carets.insert(attrs["client"].clone()) {
bail!("Multiple carets for {:?} exist", attrs["client"]);
}
}
if attrs["tag"] == "bullet" {
ensure!(!span.is_empty(), "Expected non-empty bullet");
}
ctx.stack.push(attrs.clone());
validate_doc_span(ctx, span)?;
ctx.stack.pop();
if let Some(parent) = ctx.stack.last() {
let parent_type = RtfSchema::track_type_from_attrs(parent).unwrap();
let cur_type = RtfSchema::track_type_from_attrs(attrs).unwrap();
ensure!(
cur_type.parents().contains(&parent_type),
"Block has incorrect parent"
);
} else {
ensure!(
RtfSchema::track_type_from_attrs(attrs).unwrap().allowed_in_root(),
"Root block has incorrect parent"
);
}
}
DocChars(ref text) => {
ensure!(text.char_len() > 0, "Empty char string");
if let Some(block) = ctx.stack.last() {
ensure!(
RtfSchema::track_type_from_attrs(block).unwrap().supports_text(),
"Char found outside block"
);
} else {
bail!("Found char in root");
}
}
}
}
Ok(())
}
pub fn validate_doc(doc: &Doc) -> Result<(), Error> {
let mut ctx = ValidateContext::new();
validate_doc_span(&mut ctx, &doc.0)
}