source_span/
loc.rs

1use std::convert::{
2	AsRef,
3	AsMut
4};
5use std::ops::{
6	Deref,
7	DerefMut
8};
9use std::hash::{
10	Hash,
11	Hasher
12};
13use std::cmp::{
14	Ord,
15	PartialOrd,
16	Ordering
17};
18use std::convert::TryInto;
19use std::fmt;
20use crate::Span;
21
22/// Located data.
23///
24/// This is a simple wrapper around data that can be located in a source file.
25/// It is useful to wrap abstract syntax tree nodes.
26///
27/// It derefs into the inner value.
28pub struct Loc<T: ?Sized> {
29	span: Span,
30	value: T
31}
32
33impl<T: ?Sized> Loc<T> {
34	/// Associate a span location to some data by wrapping it under `Loc`.
35	pub fn new(t: T, span: Span) -> Loc<T> where T: Sized {
36		Self {
37			span: span,
38			value: t
39		}
40	}
41
42	/// Get the span location of the data.
43	pub fn span(&self) -> Span {
44		self.span
45	}
46
47	/// Maps the inner value using the given function.
48	pub fn map<U, F>(self, f: F) -> Loc<U> where F: FnOnce(T) -> U, T: Sized {
49		Loc {
50			span: self.span,
51			value: f(self.value)
52		}
53	}
54
55	/// Convert the inner value.
56	pub fn inner_into<U>(self) -> Loc<U> where T: Into<U> {
57		Loc {
58			span: self.span,
59			value: self.value.into()
60		}
61	}
62
63	/// Tries to map the inner value using the given function.
64	pub fn try_map<U, F, E>(self, f: F) -> Result<Loc<U>, E> where F: FnOnce(T) -> Result<U, E>, T: Sized {
65		Ok(Loc {
66			span: self.span,
67			value: f(self.value)?
68		})
69	}
70
71	/// Try to convert the inner value.
72	pub fn inner_try_into<U>(self) -> Result<Loc<U>, <T as TryInto<U>>::Error> where T: TryInto<U> {
73		Ok(Loc {
74			span: self.span,
75			value: self.value.try_into()?
76		})
77	}
78
79	/// Unwrap the data.
80	pub fn into_inner(self) -> T where T: Sized {
81		self.value
82	}
83
84	/// Break the wrapper into the value and its location.
85	pub fn into_raw_parts(self) -> (T, Span) where T: Sized {
86		(self.value, self.span)
87	}
88}
89
90impl<T> Loc<Option<T>> {
91	/// Transforms a `Option<Loc<T>>` into a `Loc<Option<T>>`.
92	/// 
93	/// If the input is `None` then this function returns `Loc::new(None, span)`.
94	pub fn transposed(t: Option<Loc<T>>, span: Span) -> Self {
95		match t {
96			Some(t) => t.map(|t| Some(t)),
97			None => Self::new(None, span)
98		}
99	}
100}
101
102impl<T: Clone> Clone for Loc<T> {
103	fn clone(&self) -> Loc<T> {
104		Loc {
105			span: self.span,
106			value: self.value.clone()
107		}
108	}
109}
110
111impl<T> AsRef<T> for Loc<T> {
112	fn as_ref(&self) -> &T {
113		&self.value
114	}
115}
116
117impl<T> AsMut<T> for Loc<T> {
118	fn as_mut(&mut self) -> &mut T {
119		&mut self.value
120	}
121}
122
123impl<T: fmt::Display> fmt::Display for Loc<T> {
124	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125		self.value.fmt(f)
126	}
127}
128
129impl<T: fmt::Debug> fmt::Debug for Loc<T> {
130	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131		write!(f, "{:?}:{}", self.value, self.span)
132	}
133}
134
135impl<T: Hash> Hash for Loc<T> {
136	fn hash<H: Hasher>(&self, state: &mut H) {
137		self.span.hash(state);
138		self.value.hash(state);
139	}
140}
141
142impl<T: PartialEq> PartialEq for Loc<T> {
143	fn eq(&self, other: &Loc<T>) -> bool {
144		self.span == other.span && self.value == other.value
145	}
146}
147
148impl<T: Eq> Eq for Loc<T> {}
149
150impl<T: PartialOrd> PartialOrd for Loc<T> {
151	fn partial_cmp(&self, other: &Loc<T>) -> Option<Ordering> {
152		self.value.partial_cmp(&other.value)
153	}
154}
155
156impl<T: Ord> Ord for Loc<T> {
157	fn cmp(&self, other: &Loc<T>) -> Ordering {
158		self.value.cmp(&other.value)
159	}
160}
161
162impl<T> Deref for Loc<T> {
163	type Target = T;
164
165	fn deref(&self) -> &T {
166		&self.value
167	}
168}
169
170impl<T> DerefMut for Loc<T> {
171	fn deref_mut(&mut self) -> &mut T {
172		&mut self.value
173	}
174}