reproto_core/
source.rs

1use errors::Result;
2use ropey::Rope;
3use std::fmt;
4use std::fs::File;
5use std::io::{self, Cursor, Read};
6use std::path::{Path, PathBuf};
7use std::sync::Arc;
8use url::Url;
9use utils::{find_range, Position};
10use {Encoding, RelativePathBuf, Span};
11
12#[derive(Debug, Clone)]
13pub enum Readable {
14    Empty,
15    Bytes(Arc<Vec<u8>>),
16    Path(Arc<PathBuf>),
17    Rope(Url, Rope),
18    Stdin,
19}
20
21impl Readable {
22    /// Open a reader for this readable.
23    fn read(&self) -> Result<Box<Read>> {
24        use self::Readable::*;
25
26        let out: Box<Read> = match *self {
27            Empty => Box::new(Cursor::new(&[])),
28            Bytes(ref bytes) => Box::new(Cursor::new(ArcCursor(Arc::clone(&bytes)))),
29            Path(ref path) => Box::new(File::open(path.as_ref())?),
30            Rope(_, ref rope) => Box::new(Cursor::new(ArcCursor(Arc::new(
31                rope.to_string().into_bytes(),
32            )))),
33            Stdin => Box::new(io::stdin()),
34        };
35
36        Ok(out)
37    }
38}
39
40impl fmt::Display for Readable {
41    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
42        use self::Readable::*;
43
44        match *self {
45            Empty => "empty".fmt(fmt),
46            Bytes(ref bytes) => write!(fmt, "bytes:{}", bytes.len()),
47            Path(ref path) => write!(fmt, "path:{}", path.display()),
48            Rope(ref url, _) => write!(fmt, "rope:{}", url),
49            Stdin => "stdin".fmt(fmt),
50        }
51    }
52}
53
54#[derive(Debug, Clone)]
55pub struct Source {
56    name: Option<Arc<String>>,
57    path: Option<Arc<PathBuf>>,
58    readable: Readable,
59}
60
61impl Source {
62    /// Create a new empty source.
63    pub fn empty<S: AsRef<str>>(name: S) -> Self {
64        Self {
65            name: Some(Arc::new(name.as_ref().to_string())),
66            path: None,
67            readable: Readable::Empty,
68        }
69    }
70
71    /// Create a new empty source.
72    pub fn rope<U: Into<Url>>(url: U, rope: Rope) -> Self {
73        let url = url.into();
74
75        Self {
76            name: Some(Arc::new(url.to_string())),
77            path: None,
78            readable: Readable::Rope(url, rope),
79        }
80    }
81
82    /// Create a new bytes source.
83    pub fn bytes<S: AsRef<str>>(name: S, bytes: Vec<u8>) -> Self {
84        Self {
85            name: Some(Arc::new(name.as_ref().to_string())),
86            path: None,
87            readable: Readable::Bytes(Arc::new(bytes)),
88        }
89    }
90
91    /// Create a new path source.
92    pub fn from_path<P: AsRef<Path>>(path: P) -> Self {
93        Self {
94            name: None,
95            path: None,
96            readable: Readable::Path(Arc::new(path.as_ref().to_owned())),
97        }
98    }
99
100    /// Create an source from stdin.
101    pub fn stdin() -> Self {
102        Self {
103            name: None,
104            path: None,
105            readable: Readable::Stdin,
106        }
107    }
108
109    /// Access the path of the source.
110    pub fn path(&self) -> Option<&Path> {
111        if let Some(path) = self.path.as_ref() {
112            return Some(path.as_ref());
113        }
114
115        if let Readable::Path(ref path) = self.readable {
116            return Some(path.as_ref());
117        }
118
119        None
120    }
121
122    /// Access the URL for this source if it is a rope.
123    pub fn rope_url(&self) -> Option<&Url> {
124        if let Readable::Rope(ref url, _) = self.readable {
125            return Some(url);
126        }
127
128        None
129    }
130
131    /// Access the URL for this source.
132    pub fn url(&self) -> Option<Url> {
133        if let Readable::Rope(ref url, _) = self.readable {
134            return Some(url.clone());
135        }
136
137        if let Some(path) = self.path() {
138            let path = match path.canonicalize() {
139                Ok(path) => path,
140                Err(_) => return None,
141            };
142
143            match Url::from_file_path(path) {
144                Ok(url) => return Some(url),
145                Err(_) => {}
146            }
147        }
148
149        None
150    }
151
152    /// Access a rope.
153    pub fn as_rope(&self) -> Option<&Rope> {
154        if let Readable::Rope(_, ref rope) = self.readable {
155            return Some(rope);
156        }
157
158        None
159    }
160
161    /// Access a mutable rope.
162    pub fn as_mut_rope(&mut self) -> Option<&mut Rope> {
163        if let Readable::Rope(_, ref mut rope) = self.readable {
164            return Some(rope);
165        }
166
167        None
168    }
169
170    /// Open up a readable.
171    pub fn read(&self) -> Result<Box<Read>> {
172        self.readable.read()
173    }
174
175    /// Create a copy of this source that has a different name.
176    pub fn with_name(&self, name: String) -> Self {
177        Self {
178            name: Some(Arc::new(name)),
179            path: self.path.as_ref().map(Arc::clone),
180            readable: self.readable.clone(),
181        }
182    }
183
184    pub fn span_to_range(&self, span: Span, encoding: Encoding) -> Result<(Position, Position)> {
185        // ropes are stored in-memory and has custom facilities for solving this.
186        /*if let Some(rope) = self.as_rope() {
187            let mut start = Position::default();
188            let mut end = Position::default();
189
190            let start.line = rope.char_to_line(span.start);
191            let end.line = rope.char_to_line(span.end);
192
193            let start_line = rope.line(start.line).bytes().collect::<Vec<_>>();
194            let end_line = rope.line(end.line).bytes().collect::<Vec<_>>();
195
196            return Ok((start, end));
197        }*/
198
199        find_range(self.read()?, span, encoding)
200    }
201}
202
203impl fmt::Display for Source {
204    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
205        if let Readable::Path(ref path) = self.readable {
206            if path.is_absolute() {
207                return path.display().fmt(fmt);
208            }
209
210            // platform-neutral formatting
211            return RelativePathBuf::from_path(path.as_ref())
212                .map_err(|_| fmt::Error)?
213                .display()
214                .fmt(fmt);
215        }
216
217        match self.name {
218            Some(ref name) => write!(fmt, "<{} {}>", name, self.readable),
219            None => write!(fmt, "<{}>", self.readable),
220        }
221    }
222}
223
224/// Adapt a vector in an Arc to be used in a Cursor.
225struct ArcCursor(Arc<Vec<u8>>);
226
227impl AsRef<[u8]> for ArcCursor {
228    fn as_ref(&self) -> &[u8] {
229        self.0.as_ref()
230    }
231}