I am working on a program to map data to a canvas. I have a sample vector of structures that contains the data which will be used to calculate the pixel locations on the canvas and placed via a vector of points. With help from this forum I have worked out calculating the x axis pixels from the data with an iterator but am unable to do so for the y axis. I need to calculate the min and max data values then use the min value in a subsequent calculation to determine the pixel values. Unfortunately I have run into the borrow checker which will not let me immutably borrow the variable min_close in the map method because it is mutably borrowed in the inspect method. I do not understand how to work around this issue. Any assistance will be appreciated.
struct ClosingsByDay {
date: String,
closing: f32,
}
pub fn line_graph_x_data() -> Vec<f32> {
let date_closing_vec: Vec<ClosingsByDay> = vec![
ClosingsByDay { date: "2026-02-02".to_string(), closing: 310.05},
ClosingsByDay { date: "2026-03-14".to_string(), closing: 322.77},
ClosingsByDay { date: "2026-03-29".to_string(), closing: 302.29},
ClosingsByDay { date: "2026-04-09".to_string(), closing: 336.45},
ClosingsByDay { date: "2026-05-22".to_string(), closing: 352.95},
ClosingsByDay { date: "2026-07-15".to_string(), closing: 345.59},
];
let starting_date = NaiveDate::parse_from_str(&date_closing_vec[0].date, "%Y-%m-%d").expect("error");
let mut duration_iter = date_closing_vec
.iter()
.filter_map(|item| NaiveDate::parse_from_str(&item.date, "%Y-%m-%d").ok())
.map(|nav_date| nav_date.signed_duration_since(starting_date).num_days());
let last_duration = duration_iter.next_back().unwrap();
let x_axis = duration_iter
.map(|duration| duration as f32 / last_duration as f32)
.chain([1.0])
.map(|ratio| ((ratio * 600.0) + 100.0).round())
.collect::<Vec<f32>>();
for item in &x_axis {
println!("duration = {}", item);
}
let mut max_close = date_closing_vec[0].closing;
let mut min_close = date_closing_vec[0].closing;
let close_delta = max_close - min_close;
let y_axis = date_closing_vec
.iter()
.inspect(|element| {
if element.closing > max_close {
max_close = element.closing;
}
if element.closing < min_close {
min_close = element.closing;
}
})
.map(|element| {
(700.0 - ((element.closing - min_close) / close_delta) + 100.0).round()
// cannnot borrow min_close as immutable in above line
// already borrowed as mutable
})
.collect::<Vec<f32>>();
for item in &y_axis {
println!("y value = {}", item);
}
x_axis
}
Could you please post the full error from running cargo check (or the full error from your ide/editor if you can get it)? Often there is a lot more useful info in the error, including references to where min_close is already borrowed.
But from what you posted, I would try moving the code out of the inspect closure and combining it with the code in the map closure.
Combine those .inspect() and .map() into one:
let y_axis = date_closing_vec
.iter()
.map(|element| {
if element.closing > max_close {
max_close = element.closing;
}
if element.closing < min_close {
min_close = element.closing;
}
(700.0 - ((element.closing - min_close) / close_delta) + 100.0).round()
})
.collect::<Vec<f32>>();
Otherwise both closures must exist at once (their calls are interleaved, at that, so it's not just unfortunate interface), so their captures must not conflict.
UPD: this won't produce the wanted behavior, probably. Am I right that you want to use the minimum of whole vector rather than of the prefix? If so, you do two iterations; the first is much clearer with for rather than inspect.
Below is a more complete error message. I should have posted this initially. My error. Yes, I need both the min and max of the whole vector. I will look into changing the inspect to a for loop as suggested.
error[E0502]: cannot borrow `min_close` as immutable because it is also borrowed as mutable
--> src/views/line_graph.rs:85:14
|
76 | .inspect(|element| {
| --------- mutable borrow occurs here
...
81 | min_close = element.closing;
| --------- first borrow occurs due to use of `min_close` in closure
...
85 | .map(|element| {
| --- ^^^^^^^^^ immutable borrow occurs here
| |
| mutable borrow later used by call
86 |
87 | (700.0 - ((element.closing - min_close) / close_delta) + 100.0).round()
| --------- second borrow occurs due to use of `min_close` in closure
Your logic is somewhat off. Fixing that first may incidentally avoid (or change) the errors you're getting.
let mut max_close = date_closing_vec[0].closing;
let mut min_close = date_closing_vec[0].closing;
let close_delta = max_close - min_close;
close_delta is always 0.0. But later you divide by close_delta.
This is the pertinent question and likely solution IMO:
(The delta of the prefix will still be 0.0 for the first element.)
let mut max_close = date_closing_vec[0].closing;
let mut min_close = date_closing_vec[0].closing;
for closing in date_closing_vec.iter().map(|c| c.closing) {
max_close = max_close.max(closing);
min_close = min_close.min(closing);
}
let close_delta = max_close - min_close;
I followed the suggestion above and iterated thru the vector twice. This fixed the borrow checker issue. quinedot, you are right regarding close_delta. In addition my final calculation was wrong, I. left out the height of the actual chart (600). All has been fixed and the y_axis values are correct. Thank you one and all once again for the assistance. Below is the updated code.
let mut max_close = date_closing_vec[0].closing;
let mut min_close = date_closing_vec[0].closing;
date_closing_vec
.iter()
.for_each(|element|{
if element.closing > max_close {
max_close = element.closing
}
if element.closing < min_close {
min_close = element.closing
}
});
let delta = max_close - min_close;
let y_axis = date_closing_vec
.iter()
.map(|element| {
(700.0 - (600.0 * ((element.closing - min_close) / delta))).round()
})
.collect::<Vec<f32>>();
Unrelated to the borrowing, nonetheless relevant: itertools has minmax, but that means you will iterate twice.
let (min_close, max_close) =
date_closing_vec
.iter()
.map(|e| e.closing)
.minmax()
.into_option()
.unwrap();