1use errors::Result;
9use std::cell::{BorrowError, Ref, RefCell};
10use std::path::Path;
11use std::rc::Rc;
12use std::result;
13use {Diagnostics, Filesystem, Handle};
14
15#[derive(Debug)]
16pub enum ContextItem {
17 Diagnostics { diagnostics: Diagnostics },
19}
20
21#[derive(Clone)]
22pub struct Context {
24 filesystem: Rc<Box<Filesystem>>,
26 items: Rc<RefCell<Vec<ContextItem>>>,
28}
29
30impl Context {
31 pub fn new(filesystem: Box<Filesystem>) -> Context {
33 Context {
34 filesystem: Rc::new(filesystem),
35 items: Rc::new(RefCell::new(vec![])),
36 }
37 }
38
39 pub fn with_items(self, items: Rc<RefCell<Vec<ContextItem>>>) -> Context {
41 Context { items, ..self }
42 }
43
44 pub fn map_filesystem<F>(self, map: F) -> Self
46 where
47 F: FnOnce(Rc<Box<Filesystem>>) -> Box<Filesystem>,
48 {
49 Context {
50 filesystem: Rc::new(map(self.filesystem)),
51 ..self
52 }
53 }
54
55 pub fn filesystem(&self, root: Option<&Path>) -> Result<Box<Handle>> {
57 self.filesystem.open_root(root)
58 }
59
60 pub fn diagnostics(&self, diagnostics: Diagnostics) -> Result<()> {
62 self.items
63 .try_borrow_mut()
64 .map_err(|_| "no mutable access to context")?
65 .push(ContextItem::Diagnostics { diagnostics });
66
67 Ok(())
68 }
69
70 pub fn items(&self) -> result::Result<Ref<Vec<ContextItem>>, BorrowError> {
72 self.items.try_borrow()
73 }
74
75 pub fn has_diagnostics(&self) -> Result<bool> {
77 Ok(self.items
78 .try_borrow()
79 .map_err(|_| "immutable access to context")?
80 .iter()
81 .any(|item| match *item {
82 ContextItem::Diagnostics { ref diagnostics } => diagnostics.has_errors(),
83 }))
84 }
85
86 pub fn clear(&self) -> Result<()> {
88 self.items
89 .try_borrow_mut()
90 .map_err(|_| "no mutable access to context")?
91 .clear();
92
93 Ok(())
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use {CapturingFilesystem, Diagnostics, Source, Span};
101
102 #[test]
103 fn test_handle() {
104 let ctx = Context::new(Box::new(CapturingFilesystem::new()));
105
106 let mut diag = Diagnostics::new(Source::empty("test"));
107 diag.err(Span::empty(), "nope");
108 diag.err(Span::empty(), "previously reported here");
109 ctx.diagnostics(diag).expect("bad diagnostic");
110
111 assert_eq!(1, ctx.items().unwrap().len());
112 }
113}