1use logisheets_parser::ast;
2
3use super::super::calc_vertex::{CalcReference, CalcVertex, ColRange, Reference, RowRange};
4use logisheets_base::Addr as Address;
5
6pub fn get_range(lhs: CalcVertex, rhs: CalcVertex) -> CalcVertex {
7 match (lhs, rhs) {
8 (CalcVertex::Reference(lhs_ref), CalcVertex::Reference(rhs_ref)) => {
9 let lhs_prefix = lhs_ref.sheet;
10 let rhs_prefix = rhs_ref.sheet;
11 if lhs_prefix != rhs_prefix {
12 return CalcVertex::from_error(ast::Error::Value);
13 }
14 let result = get_range_without_prefix(lhs_ref.reference, rhs_ref.reference);
15 match result {
16 Some(r) => CalcVertex::Reference(CalcReference {
17 from_sheet: None,
18 sheet: lhs_prefix,
19 reference: r,
20 }),
21 None => CalcVertex::from_error(ast::Error::Value),
22 }
23 }
24 _ => CalcVertex::from_error(ast::Error::Value),
25 }
26}
27
28pub fn get_range_without_prefix(l_ref: Reference, r_ref: Reference) -> Option<Reference> {
29 match (l_ref, r_ref) {
30 (Reference::Addr(la), Reference::Addr(ra)) => get_range_of_addresses(la, ra),
31 (Reference::Addr(addr), Reference::ColumnRange(cr)) => {
32 get_range_of_addr_and_col_range(addr, cr)
33 }
34 (Reference::Addr(addr), Reference::RowRange(rr)) => {
35 get_range_of_addr_and_row_range(addr, rr)
36 }
37 (Reference::Addr(addr), Reference::Range(start, end)) => {
38 get_range_of_addr_and_range(addr, start, end)
39 }
40 (Reference::ColumnRange(cr), Reference::Addr(addr)) => {
41 get_range_of_addr_and_col_range(addr, cr)
42 }
43 (Reference::ColumnRange(lcr), Reference::ColumnRange(rcr)) => {
44 get_range_of_col_ranges(lcr, rcr)
45 }
46 (Reference::ColumnRange(cr), Reference::RowRange(rr)) => {
47 get_range_of_col_range_and_row_range(cr, rr)
48 }
49 (Reference::ColumnRange(cr), Reference::Range(start, end)) => {
50 get_range_of_range_and_col_range(start, end, cr)
51 }
52 (Reference::RowRange(rr), Reference::Addr(addr)) => {
53 get_range_of_addr_and_row_range(addr, rr)
54 }
55 (Reference::RowRange(rr), Reference::ColumnRange(cr)) => {
56 get_range_of_col_range_and_row_range(cr, rr)
57 }
58 (Reference::RowRange(lrr), Reference::RowRange(rrr)) => get_range_of_row_ranges(lrr, rrr),
59 (Reference::RowRange(rr), Reference::Range(start, end)) => {
60 get_range_of_range_and_row_range(start, end, rr)
61 }
62 (Reference::Range(start, end), Reference::Addr(addr)) => {
63 get_range_of_addr_and_range(addr, start, end)
64 }
65 (Reference::Range(start, end), Reference::ColumnRange(cr)) => {
66 get_range_of_range_and_col_range(start, end, cr)
67 }
68 (Reference::Range(start, end), Reference::RowRange(rr)) => {
69 get_range_of_range_and_row_range(start, end, rr)
70 }
71 (Reference::Range(left_start, left_end), Reference::Range(right_start, right_end)) => {
72 get_range_of_ranges(left_start, left_end, right_start, right_end)
73 }
74 }
75}
76
77fn get_range_of_addresses(la: Address, ra: Address) -> Option<Reference> {
78 Some(Reference::Range(la, ra))
79}
80
81fn get_range_of_ranges(
82 lr_start: Address,
83 lr_end: Address,
84 rr_start: Address,
85 rr_end: Address,
86) -> Option<Reference> {
87 let (col_start, col_end) =
88 get_range_of_intervals((lr_start.col, lr_end.col), (rr_start.col, rr_end.col));
89 let (row_start, row_end) =
90 get_range_of_intervals((lr_start.row, lr_end.row), (rr_start.row, rr_end.row));
91 Some(Reference::Range(
92 Address {
93 col: col_start,
94 row: row_start,
95 },
96 Address {
97 col: col_end,
98 row: row_end,
99 },
100 ))
101}
102
103fn get_range_of_col_ranges(lcr: ColRange, rcr: ColRange) -> Option<Reference> {
104 let (start, end) = get_range_of_intervals((lcr.start, lcr.end), (rcr.start, rcr.end));
105 Some(Reference::ColumnRange(ColRange { start, end }))
106}
107
108fn get_range_of_row_ranges(lrr: RowRange, rrr: RowRange) -> Option<Reference> {
109 let (start, end) = get_range_of_intervals((lrr.start, lrr.end), (rrr.start, rrr.end));
110 Some(Reference::RowRange(RowRange { start, end }))
111}
112
113fn get_range_of_addr_and_range(
114 addr: Address,
115 range_start: Address,
116 range_end: Address,
117) -> Option<Reference> {
118 let (col_start, col_end) =
119 get_range_of_point_and_interval(addr.col, (range_start.col, range_end.col));
120 let (row_start, row_end) =
121 get_range_of_point_and_interval(addr.row, (range_start.row, range_end.row));
122 Some(Reference::Range(
123 Address {
124 col: col_start,
125 row: row_start,
126 },
127 Address {
128 col: col_end,
129 row: row_end,
130 },
131 ))
132}
133
134fn get_range_of_addr_and_col_range(addr: Address, cr: ColRange) -> Option<Reference> {
135 let (start, end) = get_range_of_point_and_interval(addr.col, (cr.start, cr.end));
136 Some(Reference::ColumnRange(ColRange { start, end }))
137}
138
139fn get_range_of_addr_and_row_range(addr: Address, rr: RowRange) -> Option<Reference> {
140 let (start, end) = get_range_of_point_and_interval(addr.row, (rr.start, rr.end));
141 Some(Reference::RowRange(RowRange { start, end }))
142}
143
144fn get_range_of_range_and_col_range(
145 range_start: Address,
146 range_end: Address,
147 cr: ColRange,
148) -> Option<Reference> {
149 let (start, end) = get_range_of_intervals((range_start.col, range_end.col), (cr.start, cr.end));
150 Some(Reference::ColumnRange(ColRange { start, end }))
151}
152fn get_range_of_range_and_row_range(
153 range_start: Address,
154 range_end: Address,
155 rr: RowRange,
156) -> Option<Reference> {
157 let (start, end) = get_range_of_intervals((range_start.row, range_end.row), (rr.start, rr.end));
158 Some(Reference::RowRange(RowRange { start, end }))
159}
160
161fn get_range_of_col_range_and_row_range(_cr: ColRange, _rr: RowRange) -> Option<Reference> {
162 None
163}
164
165#[inline]
166fn get_range_of_intervals(
167 l_interval: (usize, usize),
168 r_interval: (usize, usize),
169) -> (usize, usize) {
170 let l_ordered = order(l_interval.0, l_interval.1);
171 let r_ordered = order(r_interval.0, r_interval.1);
172 (
173 order(l_ordered.0, r_ordered.0).0,
174 order(l_ordered.1, r_ordered.1).1,
175 )
176}
177
178#[inline]
179fn get_range_of_point_and_interval(p: usize, interval: (usize, usize)) -> (usize, usize) {
180 let ordered = order(interval.0, interval.1);
181 (order(p, ordered.0).0, order(p, ordered.1).1)
182}
183
184#[inline]
185fn order(l: usize, r: usize) -> (usize, usize) {
186 if l < r {
187 (l, r)
188 } else {
189 (r, l)
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::super::{CalcValue, Value};
196 use super::{
197 ast, get_range, get_range_without_prefix, Address, CalcReference, CalcVertex, ColRange,
198 Reference, RowRange,
199 };
200
201 #[test]
202 fn addr_test() {
203 let addr = Reference::Addr(Address { row: 2, col: 3 });
204
205 let r = get_range_without_prefix(addr.clone(), Reference::Addr(Address { row: 4, col: 1 }));
206 assert!(matches!(
207 r,
208 Some(Reference::Range(
209 Address { row: 2, col: 3 },
210 Address { row: 4, col: 1 }
211 )),
212 ));
213
214 let r = get_range_without_prefix(
215 addr.clone(),
216 Reference::Range(Address { row: 4, col: 2 }, Address { row: 6, col: 5 }),
217 );
218 assert!(matches!(
219 r,
220 Some(Reference::Range(
221 Address { row: 2, col: 2 },
222 Address { row: 6, col: 5 }
223 )),
224 ));
225
226 let r = get_range_without_prefix(
227 addr.clone(),
228 Reference::ColumnRange(ColRange { start: 1, end: 3 }),
229 );
230 assert!(matches!(
231 r,
232 Some(Reference::ColumnRange(ColRange { start: 1, end: 3 })),
233 ));
234
235 let r = get_range_without_prefix(
236 addr.clone(),
237 Reference::RowRange(RowRange { start: 5, end: 6 }),
238 );
239 assert!(matches!(
240 r,
241 Some(Reference::RowRange(RowRange { start: 2, end: 6 })),
242 ));
243 }
244
245 #[test]
246 fn range_test() {
247 let range = Reference::Range(Address { row: 6, col: 3 }, Address { row: 4, col: 6 });
248
249 let r = get_range_without_prefix(
250 range.clone(),
251 Reference::Range(Address { row: 3, col: 2 }, Address { row: 5, col: 8 }),
252 );
253 assert!(matches!(
254 r,
255 Some(Reference::Range(
256 Address { row: 3, col: 2 },
257 Address { row: 6, col: 8 }
258 )),
259 ));
260
261 let r = get_range_without_prefix(
262 range.clone(),
263 Reference::ColumnRange(ColRange { start: 1, end: 3 }),
264 );
265 assert!(matches!(
266 r,
267 Some(Reference::ColumnRange(ColRange { start: 1, end: 6 })),
268 ));
269
270 let r = get_range_without_prefix(
271 Reference::RowRange(RowRange { start: 8, end: 9 }),
272 range.clone(),
273 );
274 assert!(matches!(
275 r,
276 Some(Reference::RowRange(RowRange { start: 4, end: 9 })),
277 ));
278 }
279
280 #[test]
281 fn col_range_test() {
282 let cr = Reference::ColumnRange(ColRange { start: 3, end: 6 });
283
284 let r = get_range_without_prefix(
285 cr.clone(),
286 Reference::ColumnRange(ColRange { start: 1, end: 4 }),
287 );
288 assert!(matches!(
289 r,
290 Some(Reference::ColumnRange(ColRange { start: 1, end: 6 })),
291 ));
292
293 let r = get_range_without_prefix(
294 Reference::RowRange(RowRange { start: 8, end: 9 }),
295 cr.clone(),
296 );
297 assert!(matches!(r, None));
298 }
299
300 #[test]
301 fn row_range_test() {
302 let cr = Reference::RowRange(RowRange { start: 3, end: 6 });
303
304 let r = get_range_without_prefix(
305 Reference::RowRange(RowRange { start: 1, end: 7 }),
306 cr.clone(),
307 );
308 assert!(matches!(
309 r,
310 Some(Reference::RowRange(RowRange { start: 1, end: 7 })),
311 ));
312 }
313 #[test]
314 fn prefix_test() {
315 let cv1 = CalcVertex::Reference(CalcReference {
316 from_sheet: None,
317 sheet: 1,
318 reference: Reference::Addr(Address { row: 1, col: 1 }),
319 });
320 let cv2 = CalcVertex::Reference(CalcReference {
321 from_sheet: None,
322 sheet: 1,
323 reference: Reference::Addr(Address { row: 2, col: 2 }),
324 });
325 let r = get_range(cv1, cv2);
326 assert!(matches!(
327 r,
328 CalcVertex::Reference(CalcReference {
329 from_sheet: None,
330 sheet: 1,
331 reference: Reference::Range(Address { row: 1, col: 1 }, Address { row: 2, col: 2 },)
332 })
333 ));
334
335 let cv1 = CalcVertex::Reference(CalcReference {
336 from_sheet: None,
337 sheet: 1,
338 reference: Reference::Addr(Address { row: 1, col: 1 }),
339 });
340 let cv2 = CalcVertex::Reference(CalcReference {
341 from_sheet: None,
342 sheet: 2,
343 reference: Reference::Addr(Address { row: 1, col: 1 }),
344 });
345 let r = get_range(cv1, cv2);
346 assert!(matches!(
347 r,
348 CalcVertex::Value(CalcValue::Scalar(Value::Error(ast::Error::Value))),
349 ))
350 }
351}